Skip to content

Commit 6723654

Browse files
ChangSeokBaesuryasaimadhu
authored andcommitted
x86/fpu: Update XFD state where required
The IA32_XFD_MSR allows to arm #NM traps for XSTATE components which are enabled in XCR0. The register has to be restored before the tasks XSTATE is restored. The life time rules are the same as for FPU state. XFD is updated on return to userspace only when the FPU state of the task is not up to date in the registers. It's updated before the XRSTORS so that eventually enabled dynamic features are restored as well and not brought into init state. Also in signal handling for restoring FPU state from user space the correctness of the XFD state has to be ensured. Add it to CPU initialization and resume as well. Signed-off-by: Chang S. Bae <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5529acf commit 6723654

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

arch/x86/kernel/fpu/context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static inline void fpregs_restore_userregs(void)
6969
* correct because it was either set in switch_to() or in
7070
* flush_thread(). So it is excluded because it might be
7171
* not up to date in current->thread.fpu.xsave state.
72+
*
73+
* XFD state is handled in restore_fpregs_from_fpstate().
7274
*/
7375
restore_fpregs_from_fpstate(fpu->fpstate, XFEATURE_MASK_FPSTATE);
7476

arch/x86/kernel/fpu/core.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ void restore_fpregs_from_fpstate(struct fpstate *fpstate, u64 mask)
155155
}
156156

157157
if (use_xsave()) {
158+
/*
159+
* Dynamically enabled features are enabled in XCR0, but
160+
* usage requires also that the corresponding bits in XFD
161+
* are cleared. If the bits are set then using a related
162+
* instruction will raise #NM. This allows to do the
163+
* allocation of the larger FPU buffer lazy from #NM or if
164+
* the task has no permission to kill it which would happen
165+
* via #UD if the feature is disabled in XCR0.
166+
*
167+
* XFD state is following the same life time rules as
168+
* XSTATE and to restore state correctly XFD has to be
169+
* updated before XRSTORS otherwise the component would
170+
* stay in or go into init state even if the bits are set
171+
* in fpstate::regs::xsave::xfeatures.
172+
*/
173+
xfd_update_state(fpstate);
174+
158175
/*
159176
* Restoring state always needs to modify all features
160177
* which are in @mask even if the current task cannot use
@@ -241,8 +258,17 @@ int fpu_swap_kvm_fpstate(struct fpu_guest *guest_fpu, bool enter_guest)
241258

242259
cur_fps = fpu->fpstate;
243260

244-
if (!cur_fps->is_confidential)
261+
if (!cur_fps->is_confidential) {
262+
/* Includes XFD update */
245263
restore_fpregs_from_fpstate(cur_fps, XFEATURE_MASK_FPSTATE);
264+
} else {
265+
/*
266+
* XSTATE is restored by firmware from encrypted
267+
* memory. Make sure XFD state is correct while
268+
* running with guest fpstate
269+
*/
270+
xfd_update_state(cur_fps);
271+
}
246272

247273
fpregs_mark_activate();
248274
fpregs_unlock();

arch/x86/kernel/fpu/signal.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore,
282282

283283
retry:
284284
fpregs_lock();
285+
/* Ensure that XFD is up to date */
286+
xfd_update_state(fpu->fpstate);
285287
pagefault_disable();
286288
ret = __restore_fpregs_from_user(buf, fpu->fpstate->user_xfeatures,
287289
xrestore, fx_only);

arch/x86/kernel/fpu/xstate.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ void fpu__init_cpu_xstate(void)
136136

137137
cr4_set_bits(X86_CR4_OSXSAVE);
138138

139+
/*
140+
* Must happen after CR4 setup and before xsetbv() to allow KVM
141+
* lazy passthrough. Write independent of the dynamic state static
142+
* key as that does not work on the boot CPU. This also ensures
143+
* that any stale state is wiped out from XFD.
144+
*/
145+
if (cpu_feature_enabled(X86_FEATURE_XFD))
146+
wrmsrl(MSR_IA32_XFD, init_fpstate.xfd);
147+
139148
/*
140149
* XCR_XFEATURE_ENABLED_MASK (aka. XCR0) sets user features
141150
* managed by XSAVE{C, OPT, S} and XRSTOR{S}. Only XSAVE user
@@ -875,6 +884,9 @@ void fpu__resume_cpu(void)
875884
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() |
876885
xfeatures_mask_independent());
877886
}
887+
888+
if (fpu_state_size_dynamic())
889+
wrmsrl(MSR_IA32_XFD, current->thread.fpu.fpstate->xfd);
878890
}
879891

880892
/*

arch/x86/kernel/fpu/xstate.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,22 @@ extern void xfd_validate_state(struct fpstate *fpstate, u64 mask, bool rstor);
136136
static inline void xfd_validate_state(struct fpstate *fpstate, u64 mask, bool rstor) { }
137137
#endif
138138

139+
#ifdef CONFIG_X86_64
140+
static inline void xfd_update_state(struct fpstate *fpstate)
141+
{
142+
if (fpu_state_size_dynamic()) {
143+
u64 xfd = fpstate->xfd;
144+
145+
if (__this_cpu_read(xfd_state) != xfd) {
146+
wrmsrl(MSR_IA32_XFD, xfd);
147+
__this_cpu_write(xfd_state, xfd);
148+
}
149+
}
150+
}
151+
#else
152+
static inline void xfd_update_state(struct fpstate *fpstate) { }
153+
#endif
154+
139155
/*
140156
* Save processor xstate to xsave area.
141157
*
@@ -247,7 +263,8 @@ static inline int os_xrstor_safe(struct fpstate *fpstate, u64 mask)
247263
u32 hmask = mask >> 32;
248264
int err;
249265

250-
/* Must enforce XFD update here */
266+
/* Ensure that XFD is up to date */
267+
xfd_update_state(fpstate);
251268

252269
if (cpu_feature_enabled(X86_FEATURE_XSAVES))
253270
XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);

0 commit comments

Comments
 (0)