aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2015-06-07 14:37:00 -0400
committerIngo Molnar <mingo@kernel.org>2015-06-09 06:24:29 -0400
commit04cd027bcba1ead7bfe39e7f1c6f4d993c4c3323 (patch)
tree627dc0958865e561c958486b0b2af7f86a542f3c
parent0c4109bec0a6cde471bef3a21cd6f8384a614469 (diff)
x86/fpu/xstate: Wrap get_xsave_addr() to make it safer
The MPX code appears is calling a low-level FPU function (copy_fpregs_to_fpstate()). This function is not able to be called in all contexts, although it is safe to call directly in some cases. Although probably correct, the current code is ugly and potentially error-prone. So, add a wrapper that calls the (slightly) higher-level fpu__save() (which is preempt- safe) and also ensures that we even *have* an FPU context (in the case that this was called when in lazy FPU mode). Ingo had this to say about the details about when we need preemption disabled: > it's indeed generally unsafe to access/copy FPU registers with preemption enabled, > for two reasons: > > - on older systems that use FSAVE the instruction destroys FPU register > contents, which has to be handled carefully > > - even on newer systems if we copy to FPU registers (which this code doesn't) > then we don't want a context switch to occur in the middle of it, because a > context switch will write to the fpstate, potentially overwriting our new data > with old FPU state. > > But it's safe to access FPU registers with preemption enabled in a couple of > special cases: > > - potentially destructively saving FPU registers: the signal handling code does > this in copy_fpstate_to_sigframe(), because it can rely on the signal restore > side to restore the original FPU state. > > - reading FPU registers on modern systems: we don't do this anywhere at the > moment, mostly to keep symmetry with older systems where FSAVE is > destructive. > > - initializing FPU registers on modern systems: fpu__clear() does this. Here > it's safe because we don't copy from the fpstate. > > - directly writing FPU registers from user-space memory (!). We do this in > fpu__restore_sig(), and it's safe because neither context switches nor > irq-handler FPU use can corrupt the source context of the copy (which is > user-space memory). > > Note that the MPX code's current use of copy_fpregs_to_fpstate() was safe I think, > because: > > - MPX is predicated on eagerfpu, so the destructive F[N]SAVE instruction won't be > used. > > - the code was only reading FPU registers, and was doing it only in places that > guaranteed that an FPU state was already active (i.e. didn't do it in > kthreads) Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Dave Hansen <dave@sr71.net> Cc: Fenghua Yu <fenghua.yu@intel.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: Rik van Riel <riel@redhat.com> Cc: Suresh Siddha <sbsiddha@gmail.com> Cc: bp@alien8.de Link: http://lkml.kernel.org/r/20150607183700.AA881696@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/fpu/xstate.h1
-rw-r--r--arch/x86/kernel/fpu/xstate.c32
2 files changed, 33 insertions, 0 deletions
diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h
index 339894669117..4656b25bb9a7 100644
--- a/arch/x86/include/asm/fpu/xstate.h
+++ b/arch/x86/include/asm/fpu/xstate.h
@@ -41,5 +41,6 @@ extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
41extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); 41extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
42 42
43void *get_xsave_addr(struct xregs_state *xsave, int xstate); 43void *get_xsave_addr(struct xregs_state *xsave, int xstate);
44const void *get_xsave_field_ptr(int xstate_field);
44 45
45#endif 46#endif
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index af3700e0dbd2..49d0d9b2a60a 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -427,3 +427,35 @@ void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
427 return (void *)xsave + xstate_comp_offsets[feature_nr]; 427 return (void *)xsave + xstate_comp_offsets[feature_nr];
428} 428}
429EXPORT_SYMBOL_GPL(get_xsave_addr); 429EXPORT_SYMBOL_GPL(get_xsave_addr);
430
431/*
432 * This wraps up the common operations that need to occur when retrieving
433 * data from xsave state. It first ensures that the current task was
434 * using the FPU and retrieves the data in to a buffer. It then calculates
435 * the offset of the requested field in the buffer.
436 *
437 * This function is safe to call whether the FPU is in use or not.
438 *
439 * Note that this only works on the current task.
440 *
441 * Inputs:
442 * @xsave_state: state which is defined in xsave.h (e.g. XSTATE_FP,
443 * XSTATE_SSE, etc...)
444 * Output:
445 * address of the state in the xsave area or NULL if the state
446 * is not present or is in its 'init state'.
447 */
448const void *get_xsave_field_ptr(int xsave_state)
449{
450 struct fpu *fpu = &current->thread.fpu;
451
452 if (!fpu->fpstate_active)
453 return NULL;
454 /*
455 * fpu__save() takes the CPU's xstate registers
456 * and saves them off to the 'fpu memory buffer.
457 */
458 fpu__save(fpu);
459
460 return get_xsave_addr(&fpu->state.xsave, xsave_state);
461}