Commit eda32f4f authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Borislav Petkov

x86/fpu: Rework restore_regs_from_fpstate()

xfeatures_mask_fpstate() is no longer valid when dynamically enabled
features come into play.

Rework restore_regs_from_fpstate() so it takes a constant mask which will
then be applied against the maximum feature set so that the restore
operation brings all features which are not in the xsave buffer xfeature
bitmap into init state.

This ensures that if the previous task used a dynamically enabled feature
that the task which restores has all unused components properly initialized.

Cleanup the last user of xfeatures_mask_fpstate() as well and remove it.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20211014230739.461348278@linutronix.de
parent daddee24
...@@ -78,30 +78,17 @@ ...@@ -78,30 +78,17 @@
XFEATURE_MASK_INDEPENDENT | \ XFEATURE_MASK_INDEPENDENT | \
XFEATURE_MASK_SUPERVISOR_UNSUPPORTED) XFEATURE_MASK_SUPERVISOR_UNSUPPORTED)
static inline u64 xfeatures_mask_supervisor(void)
{
return fpu_kernel_cfg.max_features & XFEATURE_MASK_SUPERVISOR_SUPPORTED;
}
/* /*
* The xfeatures which are restored by the kernel when returning to user * The feature mask required to restore FPU state:
* mode. This is not necessarily the same as xfeatures_mask_uabi() as the * - All user states which are not eagerly switched in switch_to()/exec()
* kernel does not manage all XCR0 enabled features via xsave/xrstor as * - The suporvisor states
* some of them have to be switched eagerly on context switch and exec().
*/ */
static inline u64 xfeatures_mask_restore_user(void) #define XFEATURE_MASK_FPSTATE (XFEATURE_MASK_USER_RESTORE | \
{ XFEATURE_MASK_SUPERVISOR_SUPPORTED)
return fpu_kernel_cfg.max_features & XFEATURE_MASK_USER_RESTORE;
}
/* static inline u64 xfeatures_mask_supervisor(void)
* Like xfeatures_mask_restore_user() but additionally restors the
* supported supervisor states.
*/
static inline u64 xfeatures_mask_fpstate(void)
{ {
return fpu_kernel_cfg.max_features & \ return fpu_kernel_cfg.max_features & XFEATURE_MASK_SUPERVISOR_SUPPORTED;
(XFEATURE_MASK_USER_RESTORE | XFEATURE_MASK_SUPERVISOR_SUPPORTED);
} }
static inline u64 xfeatures_mask_independent(void) static inline u64 xfeatures_mask_independent(void)
......
...@@ -61,8 +61,6 @@ static inline void fpregs_restore_userregs(void) ...@@ -61,8 +61,6 @@ static inline void fpregs_restore_userregs(void)
return; return;
if (!fpregs_state_valid(fpu, cpu)) { if (!fpregs_state_valid(fpu, cpu)) {
u64 mask;
/* /*
* This restores _all_ xstate which has not been * This restores _all_ xstate which has not been
* established yet. * established yet.
...@@ -72,9 +70,7 @@ static inline void fpregs_restore_userregs(void) ...@@ -72,9 +70,7 @@ static inline void fpregs_restore_userregs(void)
* flush_thread(). So it is excluded because it might be * flush_thread(). So it is excluded because it might be
* not up to date in current->thread.fpu.xsave state. * not up to date in current->thread.fpu.xsave state.
*/ */
mask = xfeatures_mask_restore_user() | restore_fpregs_from_fpstate(fpu->fpstate, XFEATURE_MASK_FPSTATE);
xfeatures_mask_supervisor();
restore_fpregs_from_fpstate(fpu->fpstate, mask);
fpregs_activate(fpu); fpregs_activate(fpu);
fpu->last_cpu = cpu; fpu->last_cpu = cpu;
......
...@@ -150,6 +150,17 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask) ...@@ -150,6 +150,17 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)
} }
if (use_xsave()) { if (use_xsave()) {
/*
* Restoring state always needs to modify all features
* which are in @mask even if the current task cannot use
* extended features.
*
* So fpstate->xfeatures cannot be used here, because then
* a feature for which the task has no permission but was
* used by the previous task would not go into init state.
*/
mask = fpu_kernel_cfg.max_features & mask;
os_xrstor(&fpstate->regs.xsave, mask); os_xrstor(&fpstate->regs.xsave, mask);
} else { } else {
if (use_fxsr()) if (use_fxsr())
...@@ -161,7 +172,7 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask) ...@@ -161,7 +172,7 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)
void fpu_reset_from_exception_fixup(void) void fpu_reset_from_exception_fixup(void)
{ {
restore_fpregs_from_fpstate(&init_fpstate, xfeatures_mask_fpstate()); restore_fpregs_from_fpstate(&init_fpstate, XFEATURE_MASK_FPSTATE);
} }
#if IS_ENABLED(CONFIG_KVM) #if IS_ENABLED(CONFIG_KVM)
...@@ -179,7 +190,7 @@ void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask) ...@@ -179,7 +190,7 @@ void fpu_swap_kvm_fpu(struct fpu *save, struct fpu *rstor, u64 restore_mask)
} }
if (rstor) { if (rstor) {
restore_mask &= xfeatures_mask_fpstate(); restore_mask &= XFEATURE_MASK_FPSTATE;
restore_fpregs_from_fpstate(rstor->fpstate, restore_mask); restore_fpregs_from_fpstate(rstor->fpstate, restore_mask);
} }
...@@ -518,7 +529,7 @@ void fpu__clear_user_states(struct fpu *fpu) ...@@ -518,7 +529,7 @@ void fpu__clear_user_states(struct fpu *fpu)
} }
/* Reset user states in registers. */ /* Reset user states in registers. */
restore_fpregs_from_init_fpstate(xfeatures_mask_restore_user()); restore_fpregs_from_init_fpstate(XFEATURE_MASK_USER_RESTORE);
/* /*
* Now all FPU registers have their desired values. Inform the FPU * Now all FPU registers have their desired values. Inform the FPU
......
...@@ -344,7 +344,7 @@ static void __init print_xstate_offset_size(void) ...@@ -344,7 +344,7 @@ static void __init print_xstate_offset_size(void)
*/ */
static __init void os_xrstor_booting(struct xregs_state *xstate) static __init void os_xrstor_booting(struct xregs_state *xstate)
{ {
u64 mask = xfeatures_mask_fpstate(); u64 mask = fpu_kernel_cfg.max_features & XFEATURE_MASK_FPSTATE;
u32 lmask = mask; u32 lmask = mask;
u32 hmask = mask >> 32; u32 hmask = mask >> 32;
int err; int err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment