core_set_legacy_ssbd() counts the number of times SSBD is being enabled
via LS_CFG on a core. This assumes that calls there only occur if the
state actually changes. While svm_ctxt_switch_{to,from}() conform to
this, guest_wrmsr() doesn't: It also calls the function when the bit
doesn't actually change. Extend the conditional there accordingly.

Fixes: b2030e6730a2 ("amd/virt_ssbd: set SSBD at vCPU context switch")
Reported-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Jan Beulich <jbeul...@suse.com>
---
This is the less intrusive but more fragile variant of a fix. The
alternative would be to have core_set_legacy_ssbd() record per-thread
state, such that the necessary checking can be done there.

This wants properly testing on affected hardware. From Andrew's
description it's also not clear whether this really is addressing that
problem, or yet another one in this same area.

--- a/xen/arch/x86/msr.c
+++ b/xen/arch/x86/msr.c
@@ -699,12 +699,16 @@ int guest_wrmsr(struct vcpu *v, uint32_t
         }
         else
         {
+            uint64_t orig = msrs->virt_spec_ctrl.raw;
+
             msrs->virt_spec_ctrl.raw = val & SPEC_CTRL_SSBD;
-            if ( v == curr )
-                /*
-                 * Propagate the value to hardware, as it won't be set on guest
-                 * resume path.
-                 */
+            if ( v == curr &&
+                 /*
+                  * Propagate the value to hardware, as it won't be set on 
guest
+                  * resume path. But only do so if the bit actually changed, to
+                  * avoid issues with core_set_legacy_ssbd()'s refcounting.
+                  */
+                 ((val ^ orig) & SPEC_CTRL_SSBD) )
                 amd_set_legacy_ssbd(val & SPEC_CTRL_SSBD);
         }
         break;

Reply via email to