x86: Cleanup cr0.TS flag handling

Setting/clearing the cr0.TS bit is serializing and setting the cr0.TS
bit in particular requires a write to CR0 which is implemented in
microcode and is very slow. Therefore and with lazy FPU removed, avoid
setting/clearing the cr0.TS flag on context switch except when
saving/restoring the FPU for a PV guest.

After this, Xen's context switch code and idle CPUs run with the TS bit
cleared. An unfortunate side effect of this is that any mistaken use of
XMM registers or extended state will not trap and will therefore be more
difficult to detect.

Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Ross Lagerwall authored and Andrew Cooper committed 2026-03-30 15:48:13 +01:00
1 parent 7eb3d8420d
commit 1792bb9a99
5 files changed
+4 -35

No files matched your search

-3
View File
@@ -887,9 +887,6 @@ void cpu_init(void)
/* Install correct page table. */
write_ptbase(current);
/* Ensure FPU gets initialised for each domain. */
stts();
/* Reset debug registers: */
write_debugreg(0, 0);
write_debugreg(1, 0);
+2 -12
View File
@@ -2527,14 +2527,8 @@ static int cf_check hvmemul_get_fpu(
* Latch current register state so that we can back out changes
* if needed (namely when a memory write fails after register state
* has already been updated).
* NB: We don't really need the "enable" part of the called function
* (->fpu_dirtied set implies CR0.TS clear), but the additional
* overhead should be low enough to not warrant introduction of yet
* another slightly different function. However, we need to undo the
* ->fpu_dirtied clearing the function does as well as the possible
* masking of all exceptions by FNSTENV.)
*/
save_fpu_enable();
vcpu_save_fpu(curr);
if ( (fpu_ctxt->fcw & 0x3f) != 0x3f )
{
uint16_t fcw;
@@ -2572,12 +2566,8 @@ static void cf_check hvmemul_put_fpu(
* Latch current register state so that we can replace FIP/FDP/FOP
* (which have values resulting from our own invocation of the FPU
* instruction during emulation).
* NB: See also the comment in hvmemul_get_fpu(); we don't need to
* set ->fpu_dirtied here as it is going to be cleared below, and
* we also don't need to reload FCW as we're forcing full state to
* be reloaded anyway.
*/
save_fpu_enable();
vcpu_save_fpu(curr);
if ( boot_cpu_has(X86_FEATURE_FDP_EXCP_ONLY) &&
!(fpu_ctxt->fsw & ~fpu_ctxt->fcw & 0x003f) )
+1 -18
View File
@@ -176,9 +176,6 @@ void vcpu_restore_fpu(struct vcpu *v)
{
ASSERT(!is_idle_vcpu(v));
/* Avoid recursion */
clts();
if ( cpu_has_xsave )
fpu_xrstor(v, XSTATE_ALL);
else
@@ -193,7 +190,7 @@ void vcpu_restore_fpu(struct vcpu *v)
* On each context switch, save the necessary FPU info of VCPU being switch
* out. It dispatches saving operation based on CPU's capability.
*/
static bool _vcpu_save_fpu(struct vcpu *v)
void vcpu_save_fpu(struct vcpu *v)
{
ASSERT(!is_idle_vcpu(v));
@@ -204,20 +201,6 @@ static bool _vcpu_save_fpu(struct vcpu *v)
fpu_xsave(v);
else
fpu_fxsave(v);
return true;
}
void vcpu_save_fpu(struct vcpu *v)
{
_vcpu_save_fpu(v);
stts();
}
void save_fpu_enable(void)
{
if ( !_vcpu_save_fpu(current) )
clts();
}
/* Initialize FPU's context save area */
-1
View File
@@ -29,7 +29,6 @@ struct ix87_env {
void vcpu_restore_fpu(struct vcpu *v);
void vcpu_save_fpu(struct vcpu *v);
void save_fpu_enable(void);
int vcpu_init_fpu(struct vcpu *v);
void vcpu_destroy_fpu(struct vcpu *v);
+1 -1
View File
@@ -94,7 +94,7 @@ struct efi_rs_state efi_rs_enter(void)
return state;
state.cr3 = read_cr3();
save_fpu_enable();
vcpu_save_fpu(current);
asm volatile ( "fnclex; fldcw %0" :: "m" (fcw) );
asm volatile ( "ldmxcsr %0" :: "m" (mxcsr) );
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.