From: David Woodhouse Date: Fri, 15 Sep 2023 10:42:57 +0000 (+0200) Subject: KVM: x86: Either yield() or exit to userspace when emulating MWAIT X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fhltexit;p=users%2Fdwmw2%2Flinux.git KVM: x86: Either yield() or exit to userspace when emulating MWAIT 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 --- diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3bc2354670b07..6e991df54d5a1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -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); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 9624987bd6c35..41a1ae721a7e4 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -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 {