]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
x86/pv: fix emulation of wb{,no}invd to flush all pCPU caches
authorRoger Pau Monne <roger.pau@citrix.com>
Tue, 6 May 2025 07:28:17 +0000 (09:28 +0200)
committerRoger Pau Monne <roger.pau@citrix.com>
Tue, 6 May 2025 08:02:36 +0000 (10:02 +0200)
The current emulation of wb{,no}invd is bogus for PV guests: it will only
flush the current pCPU cache, without taking into account pCPUs where the
vCPU had run previously.  Since there's no tracking of dirty cache pCPUs
currently, resort to flushing the cache on all host pCPUs.  Also as a
result of having no mechanism to broadcast a wbnoinvd instruction, resort
to emulating it using wbinvd behavior, which is more expensive performance
wise, but correct.

Fixes: 2f6070f0b988 ("Priv-op emulation in Xen, for RDMSR/WRMSR/WBINVD")
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Note further patches will limit the broadcast cache flush to only pCPU
where the vCPU has ran.

xen/arch/x86/pv/emul-priv-op.c

index 70150c27227661baa253af8693ff00f2ab640a98..089d4cb4d9053a78d71713c864d7ee989286e10f 100644 (file)
@@ -1193,17 +1193,18 @@ static int cf_check cache_op(
 {
     ASSERT(op == x86emul_wbinvd || op == x86emul_wbnoinvd);
 
-    /* Ignore the instruction if unprivileged. */
-    if ( !cache_flush_permitted(current->domain) )
+    /*
+     * Ignore the instruction if domain doesn't have cache control.
+     * Non-physdev domain attempted WBINVD; ignore for now since
+     * newer linux uses this in some start-of-day timing loops.
+     */
+    if ( cache_flush_permitted(current->domain) )
         /*
-         * Non-physdev domain attempted WBINVD; ignore for now since
-         * newer linux uses this in some start-of-day timing loops.
+         * Handle wbnoinvd as wbinvd, at the expense of higher cost.  Broadcast
+         * the flush to all pCPUs, Xen doesn't track where the vCPU has ran
+         * previously.
          */
-        ;
-    else if ( op == x86emul_wbnoinvd /* && cpu_has_wbnoinvd */ )
-        wbnoinvd();
-    else
-        wbinvd();
+        flush_all(FLUSH_CACHE);
 
     return X86EMUL_OKAY;
 }