Skip to content

Commit 6ee8366

Browse files
rpedgecohansendc
authored andcommitted
x86/fpu: Add helper for modifying xstate
Just like user xfeatures, supervisor xfeatures can be active in the registers or present in the task FPU buffer. If the registers are active, the registers can be modified directly. If the registers are not active, the modification must be performed on the task FPU buffer. When the state is not active, the kernel could perform modifications directly to the buffer. But in order for it to do that, it needs to know where in the buffer the specific state it wants to modify is located. Doing this is not robust against optimizations that compact the FPU buffer, as each access would require computing where in the buffer it is. The easiest way to modify supervisor xfeature data is to force restore the registers and write directly to the MSRs. Often times this is just fine anyway as the registers need to be restored before returning to userspace. Do this for now, leaving buffer writing optimizations for the future. Add a new function fpregs_lock_and_load() that can simultaneously call fpregs_lock() and do this restore. Also perform some extra sanity checks in this function since this will be used in non-fpu focused code. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Rick Edgecombe <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Kees Cook <[email protected]> Acked-by: Mike Rapoport (IBM) <[email protected]> Tested-by: Pengfei Xu <[email protected]> Tested-by: John Allen <[email protected]> Tested-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/all/20230613001108.3040476-26-rick.p.edgecombe%40intel.com
1 parent 8970ef0 commit 6ee8366

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

arch/x86/include/asm/fpu/api.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ static inline void fpregs_unlock(void)
8282
preempt_enable();
8383
}
8484

85+
/*
86+
* FPU state gets lazily restored before returning to userspace. So when in the
87+
* kernel, the valid FPU state may be kept in the buffer. This function will force
88+
* restore all the fpu state to the registers early if needed, and lock them from
89+
* being automatically saved/restored. Then FPU state can be modified safely in the
90+
* registers, before unlocking with fpregs_unlock().
91+
*/
92+
void fpregs_lock_and_load(void);
93+
8594
#ifdef CONFIG_X86_DEBUG_FPU
8695
extern void fpregs_assert_state_consistent(void);
8796
#else

arch/x86/kernel/fpu/core.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,24 @@ void switch_fpu_return(void)
753753
}
754754
EXPORT_SYMBOL_GPL(switch_fpu_return);
755755

756+
void fpregs_lock_and_load(void)
757+
{
758+
/*
759+
* fpregs_lock() only disables preemption (mostly). So modifying state
760+
* in an interrupt could screw up some in progress fpregs operation.
761+
* Warn about it.
762+
*/
763+
WARN_ON_ONCE(!irq_fpu_usable());
764+
WARN_ON_ONCE(current->flags & PF_KTHREAD);
765+
766+
fpregs_lock();
767+
768+
fpregs_assert_state_consistent();
769+
770+
if (test_thread_flag(TIF_NEED_FPU_LOAD))
771+
fpregs_restore_userregs();
772+
}
773+
756774
#ifdef CONFIG_X86_DEBUG_FPU
757775
/*
758776
* If current FPU state according to its tracking (loaded FPU context on this

0 commit comments

Comments
 (0)