]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: x86: Either yield() or exit to userspace when emulating MWAIT hltexit
authorDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 15 Sep 2023 10:42:57 +0000 (12:42 +0200)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 15 Sep 2023 10:43:06 +0000 (12:43 +0200)
We don't properly emulate MWAIT; we just treat it as a no-op and return
immediately to the guest, causing it to busy-loop.

Some VMMs may want to exit to userspace in this case, so they can use
the time for other work they need to do on behalf of the guest. Otherwise,
we might as well call yield(). The semantics of that are poorly-defined
and imperfect, but it's better than nothing.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/kvm/x86.c
include/uapi/linux/kvm.h

index 3bc2354670b079315b9ba2f74044ef553167764d..6e991df54d5a1f5edda65768d531f9efa6df7d69 100644 (file)
@@ -2119,7 +2119,20 @@ static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn)
 }
 int kvm_emulate_mwait(struct kvm_vcpu *vcpu)
 {
-       return kvm_emulate_monitor_mwait(vcpu, "MWAIT");
+       int ret = kvm_emulate_monitor_mwait(vcpu, "MWAIT");
+
+       if (ret && (vcpu->kvm->arch.userspace_exits & KVM_X86_USERSPACE_EXIT_MWAIT)) {
+               vcpu->run->exit_reason = KVM_EXIT_MWAIT;
+               ret = 0;
+       } else {
+               /*
+                * Calling yield() has poorly defined semantics, but the guest is in
+                * a busy loop and it's the best we can do without properly emulating
+                * MONITOR/MWAIT (which is hard).
+                */
+               yield();
+       }
+       return ret;
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_mwait);
 
index 9624987bd6c35c5535151e3a4b777fcb98129562..41a1ae721a7e443e98562ce484878812010046b6 100644 (file)
@@ -264,6 +264,7 @@ struct kvm_xen_exit {
 #define KVM_EXIT_RISCV_SBI        35
 #define KVM_EXIT_RISCV_CSR        36
 #define KVM_EXIT_NOTIFY           37
+#define KVM_EXIT_MWAIT            38
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -843,7 +844,8 @@ struct kvm_ioeventfd {
 
 #define KVM_X86_USERSPACE_EXIT_MWAIT        (1 << 0)
 #define KVM_X86_USERSPACE_EXIT_HLT          (1 << 1)
-#define KVM_X86_USERSPACE_VALID_EXITS        (KVM_X86_USERSPACE_EXIT_HLT)
+#define KVM_X86_USERSPACE_VALID_EXITS        (KVM_X86_USERSPACE_EXIT_MWAIT | \
+                                              KVM_X86_USERSPACE_EXIT_HLT)
 
 /* for KVM_ENABLE_CAP */
 struct kvm_enable_cap {