All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior
@ 2022-06-08 22:45 Sean Christopherson
  2022-06-08 22:45 ` [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior Sean Christopherson
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Add a quirk to let userspace opt into correctly emulating MONITOR/MWAIT
when they are disabled in CPUID instead of unconditionally treating them
as NOPs.

The selftest changes are based on the CPUID overhaul[*], the KVM patch
should apply cleanly on kvm/queue, commit 55371f1d0c01 ("...").

Note!  Patch 3 is a fix for a bug in the Hyper-V Features test that I
encountered when verifying the exception fixup works as expected.  The
"bug", which is in reality a rather large set of bugs, basically turns
the test into a giant nop.  The patch really should be "backported" all
the way across the selftests overhaul, but I don't care enough about
Hyper-V to spend yet more time on selftests at this point.

[*] https://lore.kernel.org/all/20220604012058.1972195-1-seanjc@google.com

Sean Christopherson (5):
  KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior
  KVM: selftests: Add x86-64 support for exception fixup
  KVM: selftests: Mostly fix comically broken Hyper-V Features test
  KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall
    tests
  KVM: selftests: Add MONITOR/MWAIT quirk test

 Documentation/virt/kvm/api.rst                |  13 +
 arch/x86/include/asm/kvm_host.h               |   3 +-
 arch/x86/include/uapi/asm/kvm.h               |   1 +
 arch/x86/kvm/x86.c                            |  26 +-
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/include/x86_64/processor.h  |  74 ++++++
 .../selftests/kvm/lib/x86_64/processor.c      |  17 ++
 .../selftests/kvm/x86_64/hyperv_features.c    | 239 ++++++++----------
 .../selftests/kvm/x86_64/kvm_pv_test.c        |  82 ++----
 .../selftests/kvm/x86_64/monitor_mwait_test.c | 127 ++++++++++
 11 files changed, 375 insertions(+), 209 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c


base-commit: 081ad4bbae8d503c79fae45f463766d28b2f3241
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
@ 2022-06-08 22:45 ` Sean Christopherson
  2022-06-08 22:45 ` [PATCH 2/5] KVM: selftests: Add x86-64 support for exception fixup Sean Christopherson
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Add a quirk for KVM's behavior of emulating intercepted MONITOR/MWAIT
instructions a NOPs regardless of whether or not they are supported in
guest CPUID.  KVM's current behavior was likely motiviated by a certain
fruity operating system that expects MONITOR/MWAIT to be supported
unconditionally and blindly executes MONITOR/MWAIT without first checking
CPUID.  And because KVM does NOT advertise MONITOR/MWAIT to userspace,
that's effectively the default setup for any VMM that regurgitates
KVM_GET_SUPPORTED_CPUID to KVM_SET_CPUID2.

Note, this quirk interacts with KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT.  The
behavior is actually desirable, as userspace VMMs that want to
unconditionally hide MONITOR/MWAIT from the guest can leave the
MISC_ENABLE quirk enabled.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 Documentation/virt/kvm/api.rst  | 13 +++++++++++++
 arch/x86/include/asm/kvm_host.h |  3 ++-
 arch/x86/include/uapi/asm/kvm.h |  1 +
 arch/x86/kvm/x86.c              | 26 +++++++++++++++++---------
 4 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 42a1984fafc8..5c6cd8f7975f 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -7374,6 +7374,19 @@ The valid bits in cap.args[0] are:
                                     hypercall instructions. Executing the
                                     incorrect hypercall instruction will
                                     generate a #UD within the guest.
+
+KVM_X86_QUIRK_MWAIT_NEVER_FAULTS    By default, KVM emulates MONITOR/MWAIT (if
+                                    they are intercepted) as NOPs regardless of
+                                    whether or not MONITOR/MWAIT are supported
+                                    according to guest CPUID.  When this quirk
+                                    is disabled and KVM_X86_DISABLE_EXITS_MWAIT
+                                    is not set (MONITOR/MWAIT are intercepted),
+                                    KVM will inject a #UD on MONITOR/MWAIT if
+                                    they're unsupported per guest CPUID.  Note,
+                                    KVM will modify MONITOR/MWAIT support in
+                                    guest CPUID on writes to MISC_ENABLE if
+                                    KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is
+                                    disabled.
 =================================== ============================================
 
 7.32 KVM_CAP_MAX_VCPU_ID
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6cf5d77d7896..bc3e85a81f41 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2011,6 +2011,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
 	 KVM_X86_QUIRK_LAPIC_MMIO_HOLE |	\
 	 KVM_X86_QUIRK_OUT_7E_INC_RIP |		\
 	 KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT |	\
-	 KVM_X86_QUIRK_FIX_HYPERCALL_INSN)
+	 KVM_X86_QUIRK_FIX_HYPERCALL_INSN |	\
+	 KVM_X86_QUIRK_MWAIT_NEVER_FAULTS)
 
 #endif /* _ASM_X86_KVM_HOST_H */
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 24c807c8d5f7..b7c92844550b 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -438,6 +438,7 @@ struct kvm_sync_regs {
 #define KVM_X86_QUIRK_OUT_7E_INC_RIP		(1 << 3)
 #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT	(1 << 4)
 #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN	(1 << 5)
+#define KVM_X86_QUIRK_MWAIT_NEVER_FAULTS	(1 << 6)
 
 #define KVM_STATE_NESTED_FORMAT_VMX	0
 #define KVM_STATE_NESTED_FORMAT_SVM	1
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2db6f0373fa3..14abcd5c2714 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2034,13 +2034,6 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_invd);
 
-int kvm_emulate_mwait(struct kvm_vcpu *vcpu)
-{
-	pr_warn_once("kvm: MWAIT instruction emulated as NOP!\n");
-	return kvm_emulate_as_nop(vcpu);
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_mwait);
-
 int kvm_handle_invalid_op(struct kvm_vcpu *vcpu)
 {
 	kvm_queue_exception(vcpu, UD_VECTOR);
@@ -2048,10 +2041,25 @@ int kvm_handle_invalid_op(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_handle_invalid_op);
 
+
+static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn)
+{
+	if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) &&
+	    !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT))
+		return kvm_handle_invalid_op(vcpu);
+
+	pr_warn_once("kvm: %s instruction emulated as NOP!\n", insn);
+	return kvm_emulate_as_nop(vcpu);
+}
+int kvm_emulate_mwait(struct kvm_vcpu *vcpu)
+{
+	return kvm_emulate_monitor_mwait(vcpu, "MWAIT");
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_mwait);
+
 int kvm_emulate_monitor(struct kvm_vcpu *vcpu)
 {
-	pr_warn_once("kvm: MONITOR instruction emulated as NOP!\n");
-	return kvm_emulate_as_nop(vcpu);
+	return kvm_emulate_monitor_mwait(vcpu, "MONITOR");
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_monitor);
 
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/5] KVM: selftests: Add x86-64 support for exception fixup
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
  2022-06-08 22:45 ` [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior Sean Christopherson
@ 2022-06-08 22:45 ` Sean Christopherson
  2022-06-08 22:45 ` [PATCH 3/5] KVM: selftests: Mostly fix comically broken Hyper-V Features test Sean Christopherson
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Add x86-64 support for exception fixup on single instructions, without
forcing tests to install their own fault handlers.  Use registers r9-r11
to flag the instruction as "safe" and pass fixup/vector information,
i.e. introduce yet another flavor of fixup (versus the kernel's in-memory
tables and KUT's per-CPU area) to take advantage of KVM sefltests being
64-bit only.

Using only registers avoids the need to allocate fixup tables, ensure
FS or GS base is valid for the guest, ensure memory is mapped into the
guest, etc..., and also reduces the potential for recursive faults due to
accessing memory.

Providing exception fixup trivializes tests that just want to verify that
an instruction faults, e.g. no need to track start/end using global
labels, no need to install a dedicated handler, etc...

Deliberately do not support #DE in exception fixup so that the fixup glue
doesn't need to account for a fault with vector == 0, i.e. the vector can
also indicate that a fault occurred.  KVM injects #DE only for esoteric
emulation scenarios, i.e. there's very, very little value in testing #DE.
Force any test that wants to generate #DEs to install its own handler(s).

Use kvm_pv_test as a guinea pig for the new fixup, as it has a very
straightforward use case of wanting to verify that RDMSR and WRMSR fault.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 .../selftests/kvm/include/x86_64/processor.h  | 74 +++++++++++++++++
 .../selftests/kvm/lib/x86_64/processor.c      | 17 ++++
 .../selftests/kvm/x86_64/kvm_pv_test.c        | 82 ++++---------------
 3 files changed, 109 insertions(+), 64 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index 3fd3d58148c2..15aa076765a5 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -15,6 +15,8 @@
 #include <asm/msr-index.h>
 #include <asm/prctl.h>
 
+#include <linux/stringify.h>
+
 #include "../kvm_util.h"
 
 #define NMI_VECTOR		0x02
@@ -750,6 +752,78 @@ void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
 void vm_install_exception_handler(struct kvm_vm *vm, int vector,
 			void (*handler)(struct ex_regs *));
 
+/* If a toddler were to say "abracadabra". */
+#define KVM_EXCEPTION_MAGIC 0xabacadabaull
+
+/*
+ * KVM selftest exception fixup uses registers to coordinate with the exception
+ * handler, versus the kernel's in-memory tables and KVM-Unit-Tests's in-memory
+ * per-CPU data.  Using only registers avoids having to map memory into the
+ * guest, doesn't require a valid, stable GS.base, and reduces the risk of
+ * for recursive faults when accessing memory in the handler.  The downside to
+ * using registers is that it restricts what registers can be used by the actual
+ * instruction.  But, selftests are 64-bit only, making register* pressure a
+ * minor concern.  Use r9-r11 as they are volatile, i.e. don't need* to be saved
+ * by the callee, and except for r11 are not implicit parameters to any
+ * instructions.  Ideally, fixup would use r8-r10 and thus avoid implicit
+ * parameters entirely, but Hyper-V's hypercall ABI uses r8 and testing Hyper-V
+ * is higher priority than testing non-faulting SYSCALL/SYSRET.
+ *
+ * Note, the fixup handler deliberately does not handle #DE, i.e. the vector
+ * is guaranteed to be non-zero on fault.
+ *
+ * REGISTER INPUTS:
+ * r9  = MAGIC
+ * r10 = RIP
+ * r11 = new RIP on fault
+ *
+ * REGISTER OUTPUTS:
+ * r9  = exception vector (non-zero)
+ */
+#define KVM_ASM_SAFE(insn)					\
+	"mov $" __stringify(KVM_EXCEPTION_MAGIC) ", %%r9\n\t"	\
+	"lea 1f(%%rip), %%r10\n\t"				\
+	"lea 2f(%%rip), %%r11\n\t"				\
+	"1: " insn "\n\t"					\
+	"mov $0, %[vector]\n\t"					\
+	"jmp 3f\n\t"						\
+	"2:\n\t"						\
+	"mov  %%r9b, %[vector]\n\t"				\
+	"3:\n\t"
+
+#define KVM_ASM_SAFE_OUTPUTS(v)	[vector] "=qm"(v)
+#define KVM_ASM_SAFE_CLOBBERS	"r9", "r10", "r11"
+
+#define kvm_asm_safe(insn, inputs...)			\
+({							\
+	uint8_t vector;					\
+							\
+	asm volatile(KVM_ASM_SAFE(insn)			\
+		     : KVM_ASM_SAFE_OUTPUTS(vector)	\
+		     : inputs				\
+		     : KVM_ASM_SAFE_CLOBBERS);		\
+	vector;						\
+})
+
+static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val)
+{
+	uint8_t vector;
+	uint32_t a, d;
+
+	asm volatile(KVM_ASM_SAFE("rdmsr")
+		     : "=a"(a), "=d"(d), KVM_ASM_SAFE_OUTPUTS(vector)
+		     : "c"(msr)
+		     : KVM_ASM_SAFE_CLOBBERS);
+
+	*val = (uint64_t)a | ((uint64_t)d << 32);
+	return vector;
+}
+
+static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val)
+{
+	return kvm_asm_safe("wrmsr", "A"(val), "c"(msr));
+}
+
 uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
 				 uint64_t vaddr);
 void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c
index 5cb73b2f9978..95db8eebcc1d 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c
@@ -1079,6 +1079,20 @@ static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr,
 	e->offset2 = addr >> 32;
 }
 
+
+static bool kvm_fixup_exception(struct ex_regs *regs)
+{
+	if (regs->r9 != KVM_EXCEPTION_MAGIC || regs->rip != regs->r10)
+		return false;
+
+	if (regs->vector == DE_VECTOR)
+		return false;
+
+	regs->rip = regs->r11;
+	regs->r9 = regs->vector;
+	return true;
+}
+
 void kvm_exit_unexpected_vector(uint32_t value)
 {
 	ucall(UCALL_UNHANDLED, 1, value);
@@ -1094,6 +1108,9 @@ void route_exception(struct ex_regs *regs)
 		return;
 	}
 
+	if (kvm_fixup_exception(regs))
+		return;
+
 	kvm_exit_unexpected_vector(regs->vector);
 }
 
diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c
index 7ab61f3f2a20..37875e864030 100644
--- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c
+++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c
@@ -12,55 +12,6 @@
 #include "kvm_util.h"
 #include "processor.h"
 
-extern unsigned char rdmsr_start;
-extern unsigned char rdmsr_end;
-
-static u64 do_rdmsr(u32 idx)
-{
-	u32 lo, hi;
-
-	asm volatile("rdmsr_start: rdmsr;"
-		     "rdmsr_end:"
-		     : "=a"(lo), "=c"(hi)
-		     : "c"(idx));
-
-	return (((u64) hi) << 32) | lo;
-}
-
-extern unsigned char wrmsr_start;
-extern unsigned char wrmsr_end;
-
-static void do_wrmsr(u32 idx, u64 val)
-{
-	u32 lo, hi;
-
-	lo = val;
-	hi = val >> 32;
-
-	asm volatile("wrmsr_start: wrmsr;"
-		     "wrmsr_end:"
-		     : : "a"(lo), "c"(idx), "d"(hi));
-}
-
-static int nr_gp;
-
-static void guest_gp_handler(struct ex_regs *regs)
-{
-	unsigned char *rip = (unsigned char *)regs->rip;
-	bool r, w;
-
-	r = rip == &rdmsr_start;
-	w = rip == &wrmsr_start;
-	GUEST_ASSERT(r || w);
-
-	nr_gp++;
-
-	if (r)
-		regs->rip = (uint64_t)&rdmsr_end;
-	else
-		regs->rip = (uint64_t)&wrmsr_end;
-}
-
 struct msr_data {
 	uint32_t idx;
 	const char *name;
@@ -89,14 +40,16 @@ static struct msr_data msrs_to_test[] = {
 
 static void test_msr(struct msr_data *msr)
 {
+	uint64_t ignored;
+	uint8_t vector;
+
 	PR_MSR(msr);
-	do_rdmsr(msr->idx);
-	GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
 
-	nr_gp = 0;
-	do_wrmsr(msr->idx, 0);
-	GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
-	nr_gp = 0;
+	vector = rdmsr_safe(msr->idx, &ignored);
+	GUEST_ASSERT_1(vector == GP_VECTOR, vector);
+
+	vector = wrmsr_safe(msr->idx, 0);
+	GUEST_ASSERT_1(vector == GP_VECTOR, vector);
 }
 
 struct hcall_data {
@@ -156,12 +109,6 @@ static void pr_hcall(struct ucall *uc)
 	pr_info("testing hcall: %s (%lu)\n", hc->name, hc->nr);
 }
 
-static void handle_abort(struct ucall *uc)
-{
-	TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0],
-		  __FILE__, uc->args[1]);
-}
-
 static void enter_guest(struct kvm_vcpu *vcpu)
 {
 	struct kvm_run *run = vcpu->run;
@@ -181,7 +128,9 @@ static void enter_guest(struct kvm_vcpu *vcpu)
 			pr_hcall(&uc);
 			break;
 		case UCALL_ABORT:
-			handle_abort(&uc);
+			TEST_FAIL("%s at %s:%ld, vector = %lu",
+				  (const char *)uc.args[0], __FILE__,
+				  uc.args[1], uc.args[2]);
 			return;
 		case UCALL_DONE:
 			return;
@@ -191,6 +140,7 @@ static void enter_guest(struct kvm_vcpu *vcpu)
 
 int main(void)
 {
+	struct kvm_cpuid_entry2 *entry;
 	struct kvm_vcpu *vcpu;
 	struct kvm_vm *vm;
 
@@ -200,11 +150,15 @@ int main(void)
 
 	vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1);
 
-	vcpu_clear_cpuid_entry(vcpu, KVM_CPUID_FEATURES);
+	entry = vcpu_get_cpuid_entry(vcpu, KVM_CPUID_FEATURES);
+	entry->eax = 0;
+	entry->ebx = 0;
+	entry->ecx = 0;
+	entry->edx = 0;
+	vcpu_set_cpuid(vcpu);
 
 	vm_init_descriptor_tables(vm);
 	vcpu_init_descriptor_tables(vcpu);
-	vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler);
 
 	enter_guest(vcpu);
 	kvm_vm_free(vm);
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/5] KVM: selftests: Mostly fix comically broken Hyper-V Features test
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
  2022-06-08 22:45 ` [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior Sean Christopherson
  2022-06-08 22:45 ` [PATCH 2/5] KVM: selftests: Add x86-64 support for exception fixup Sean Christopherson
@ 2022-06-08 22:45 ` Sean Christopherson
  2022-06-08 22:45 ` [PATCH 4/5] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests Sean Christopherson
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Explicitly do all setup at every stage of the Hyper-V Features test, e.g.
set the MSR/hypercall, enable capabilities, etc...  Now that the VM is
recreated for every stage, values that are written into the VM's address
space, i.e. shared with the guest, are reset between sub-tests, as are
any capabilities, etc...

Fix the hypercall params as well, which were broken in the same rework.
The "hcall" struct/pointer needs to point at the hcall_params object, not
the set of hypercall pages.

The goofs were hidden by the test's dubious behavior of using '0' to
signal "done", i.e. the MSR test ran exactly one sub-test, and the
hypercall test was a gigantic nop.

Fixes: 6c1186430a80 ("KVM: selftests: Avoid KVM_SET_CPUID2 after KVM_RUN in hyperv_features test")
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 .../selftests/kvm/x86_64/hyperv_features.c    | 146 ++++++++++--------
 1 file changed, 83 insertions(+), 63 deletions(-)

diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
index 3d0df079496b..5ec40422d72a 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
@@ -101,52 +101,44 @@ struct hcall_data {
 
 static void guest_msr(struct msr_data *msr)
 {
-	int i = 0;
-
-	while (msr->idx) {
-		WRITE_ONCE(nr_gp, 0);
-		if (!msr->write)
-			do_rdmsr(msr->idx);
-		else
-			do_wrmsr(msr->idx, msr->write_val);
-
-		if (msr->available)
-			GUEST_ASSERT(READ_ONCE(nr_gp) == 0);
-		else
-			GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
-
-		GUEST_SYNC(i++);
-	}
-
+	GUEST_ASSERT(msr->idx);
+
+	WRITE_ONCE(nr_gp, 0);
+	if (!msr->write)
+		do_rdmsr(msr->idx);
+	else
+		do_wrmsr(msr->idx, msr->write_val);
+
+	if (msr->available)
+		GUEST_ASSERT(READ_ONCE(nr_gp) == 0);
+	else
+		GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
 	GUEST_DONE();
 }
 
 static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
 {
-	int i = 0;
 	u64 res, input, output;
 
+	GUEST_ASSERT(hcall->control);
+
 	wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID);
 	wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
 
-	while (hcall->control) {
-		nr_ud = 0;
-		if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
-			input = pgs_gpa;
-			output = pgs_gpa + 4096;
-		} else {
-			input = output = 0;
-		}
-
-		res = hypercall(hcall->control, input, output);
-		if (hcall->ud_expected)
-			GUEST_ASSERT(nr_ud == 1);
-		else
-			GUEST_ASSERT(res == hcall->expect);
-
-		GUEST_SYNC(i++);
+	nr_ud = 0;
+	if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
+		input = pgs_gpa;
+		output = pgs_gpa + 4096;
+	} else {
+		input = output = 0;
 	}
 
+	res = hypercall(hcall->control, input, output);
+	if (hcall->ud_expected)
+		GUEST_ASSERT(nr_ud == 1);
+	else
+		GUEST_ASSERT(res == hcall->expect);
+
 	GUEST_DONE();
 }
 
@@ -202,6 +194,10 @@ static void guest_test_msrs_access(void)
 
 		run = vcpu->run;
 
+		/* TODO: Make this entire test easier to maintain. */
+		if (stage >= 21)
+			vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0);
+
 		switch (stage) {
 		case 0:
 			/*
@@ -245,11 +241,13 @@ static void guest_test_msrs_access(void)
 			break;
 		case 6:
 			feat->eax |= HV_MSR_VP_RUNTIME_AVAILABLE;
+			msr->idx = HV_X64_MSR_VP_RUNTIME;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 7:
 			/* Read only */
+			msr->idx = HV_X64_MSR_VP_RUNTIME;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 0;
@@ -262,11 +260,13 @@ static void guest_test_msrs_access(void)
 			break;
 		case 9:
 			feat->eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE;
+			msr->idx = HV_X64_MSR_TIME_REF_COUNT;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 10:
 			/* Read only */
+			msr->idx = HV_X64_MSR_TIME_REF_COUNT;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 0;
@@ -279,11 +279,13 @@ static void guest_test_msrs_access(void)
 			break;
 		case 12:
 			feat->eax |= HV_MSR_VP_INDEX_AVAILABLE;
+			msr->idx = HV_X64_MSR_VP_INDEX;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 13:
 			/* Read only */
+			msr->idx = HV_X64_MSR_VP_INDEX;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 0;
@@ -296,10 +298,12 @@ static void guest_test_msrs_access(void)
 			break;
 		case 15:
 			feat->eax |= HV_MSR_RESET_AVAILABLE;
+			msr->idx = HV_X64_MSR_RESET;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 16:
+			msr->idx = HV_X64_MSR_RESET;
 			msr->write = 1;
 			msr->write_val = 0;
 			msr->available = 1;
@@ -312,10 +316,12 @@ static void guest_test_msrs_access(void)
 			break;
 		case 18:
 			feat->eax |= HV_MSR_REFERENCE_TSC_AVAILABLE;
+			msr->idx = HV_X64_MSR_REFERENCE_TSC;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 19:
+			msr->idx = HV_X64_MSR_REFERENCE_TSC;
 			msr->write = 1;
 			msr->write_val = 0;
 			msr->available = 1;
@@ -331,14 +337,18 @@ static void guest_test_msrs_access(void)
 			 * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2
 			 * capability enabled and guest visible CPUID bit unset.
 			 */
-			vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0);
+			msr->idx = HV_X64_MSR_EOM;
+			msr->write = 0;
+			msr->available = 0;
 			break;
 		case 22:
 			feat->eax |= HV_MSR_SYNIC_AVAILABLE;
+			msr->idx = HV_X64_MSR_EOM;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 23:
+			msr->idx = HV_X64_MSR_EOM;
 			msr->write = 1;
 			msr->write_val = 0;
 			msr->available = 1;
@@ -351,22 +361,28 @@ static void guest_test_msrs_access(void)
 			break;
 		case 25:
 			feat->eax |= HV_MSR_SYNTIMER_AVAILABLE;
+			msr->idx = HV_X64_MSR_STIMER0_CONFIG;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 26:
+			msr->idx = HV_X64_MSR_STIMER0_CONFIG;
 			msr->write = 1;
 			msr->write_val = 0;
 			msr->available = 1;
 			break;
 		case 27:
 			/* Direct mode test */
+			msr->idx = HV_X64_MSR_STIMER0_CONFIG;
 			msr->write = 1;
 			msr->write_val = 1 << 12;
 			msr->available = 0;
 			break;
 		case 28:
 			feat->edx |= HV_STIMER_DIRECT_MODE_AVAILABLE;
+			msr->idx = HV_X64_MSR_STIMER0_CONFIG;
+			msr->write = 1;
+			msr->write_val = 1 << 12;
 			msr->available = 1;
 			break;
 
@@ -377,6 +393,7 @@ static void guest_test_msrs_access(void)
 			break;
 		case 30:
 			feat->eax |= HV_MSR_APIC_ACCESS_AVAILABLE;
+			msr->idx = HV_X64_MSR_EOI;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 1;
@@ -389,11 +406,13 @@ static void guest_test_msrs_access(void)
 			break;
 		case 32:
 			feat->eax |= HV_ACCESS_FREQUENCY_MSRS;
+			msr->idx = HV_X64_MSR_TSC_FREQUENCY;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 33:
 			/* Read only */
+			msr->idx = HV_X64_MSR_TSC_FREQUENCY;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 0;
@@ -406,10 +425,12 @@ static void guest_test_msrs_access(void)
 			break;
 		case 35:
 			feat->eax |= HV_ACCESS_REENLIGHTENMENT;
+			msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 36:
+			msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 1;
@@ -429,10 +450,12 @@ static void guest_test_msrs_access(void)
 			break;
 		case 39:
 			feat->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
+			msr->idx = HV_X64_MSR_CRASH_P0;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 40:
+			msr->idx = HV_X64_MSR_CRASH_P0;
 			msr->write = 1;
 			msr->write_val = 1;
 			msr->available = 1;
@@ -446,30 +469,28 @@ static void guest_test_msrs_access(void)
 		case 42:
 			feat->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE;
 			dbg->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+			msr->idx = HV_X64_MSR_SYNDBG_STATUS;
 			msr->write = 0;
 			msr->available = 1;
 			break;
 		case 43:
+			msr->idx = HV_X64_MSR_SYNDBG_STATUS;
 			msr->write = 1;
 			msr->write_val = 0;
 			msr->available = 1;
 			break;
 
 		case 44:
-			/* END */
-			msr->idx = 0;
-			break;
+			kvm_vm_free(vm);
+			return;
 		}
 
 		vcpu_set_cpuid(vcpu);
 
 		memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent));
 
-		if (msr->idx)
-			pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage,
-				 msr->idx, msr->write ? "write" : "read");
-		else
-			pr_debug("Stage %d: finish\n", stage);
+		pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage,
+			 msr->idx, msr->write ? "write" : "read");
 
 		vcpu_run(vcpu);
 		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
@@ -477,16 +498,14 @@ static void guest_test_msrs_access(void)
 			    run->exit_reason, exit_reason_str(run->exit_reason));
 
 		switch (get_ucall(vcpu, &uc)) {
-		case UCALL_SYNC:
-			TEST_ASSERT(uc.args[1] == 0,
-				    "Unexpected stage: %ld (0 expected)\n",
-				    uc.args[1]);
-			break;
 		case UCALL_ABORT:
 			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
 				  __FILE__, uc.args[1]);
 			return;
 		case UCALL_DONE:
+			break;
+		default:
+			TEST_FAIL("Unhandled ucall: %ld", uc.cmd);
 			return;
 		}
 
@@ -516,11 +535,11 @@ static void guest_test_hcalls_access(void)
 
 		/* Hypercall input/output */
 		hcall_page = vm_vaddr_alloc_pages(vm, 2);
-		hcall = addr_gva2hva(vm, hcall_page);
 		memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize());
 
 		hcall_params = vm_vaddr_alloc_page(vm);
 		memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize());
+		hcall = addr_gva2hva(vm, hcall_params);
 
 		vcpu_args_set(vcpu, 2, addr_gva2gpa(vm, hcall_page), hcall_params);
 		vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1);
@@ -552,6 +571,7 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 2:
 			feat->ebx |= HV_POST_MESSAGES;
+			hcall->control = HVCALL_POST_MESSAGE;
 			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
 			break;
 
@@ -561,6 +581,7 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 4:
 			feat->ebx |= HV_SIGNAL_EVENTS;
+			hcall->control = HVCALL_SIGNAL_EVENT;
 			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
 			break;
 
@@ -570,10 +591,12 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 6:
 			dbg->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+			hcall->control = HVCALL_RESET_DEBUG_SESSION;
 			hcall->expect = HV_STATUS_ACCESS_DENIED;
 			break;
 		case 7:
 			feat->ebx |= HV_DEBUGGING;
+			hcall->control = HVCALL_RESET_DEBUG_SESSION;
 			hcall->expect = HV_STATUS_OPERATION_DENIED;
 			break;
 
@@ -583,6 +606,7 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 9:
 			recomm->eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED;
+			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE;
 			hcall->expect = HV_STATUS_SUCCESS;
 			break;
 		case 10:
@@ -591,6 +615,7 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 11:
 			recomm->eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED;
+			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX;
 			hcall->expect = HV_STATUS_SUCCESS;
 			break;
 
@@ -600,6 +625,7 @@ static void guest_test_hcalls_access(void)
 			break;
 		case 13:
 			recomm->eax |= HV_X64_CLUSTER_IPI_RECOMMENDED;
+			hcall->control = HVCALL_SEND_IPI;
 			hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT;
 			break;
 		case 14:
@@ -613,6 +639,7 @@ static void guest_test_hcalls_access(void)
 			hcall->expect = HV_STATUS_ACCESS_DENIED;
 			break;
 		case 16:
+			hcall->control = HVCALL_NOTIFY_LONG_SPIN_WAIT;
 			recomm->ebx = 0xfff;
 			hcall->expect = HV_STATUS_SUCCESS;
 			break;
@@ -622,26 +649,21 @@ static void guest_test_hcalls_access(void)
 			hcall->ud_expected = true;
 			break;
 		case 18:
+			hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FAST_BIT;
 			feat->edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE;
 			hcall->ud_expected = false;
 			hcall->expect = HV_STATUS_SUCCESS;
 			break;
-
 		case 19:
-			/* END */
-			hcall->control = 0;
-			break;
+			kvm_vm_free(vm);
+			return;
 		}
 
 		vcpu_set_cpuid(vcpu);
 
 		memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent));
 
-		if (hcall->control)
-			pr_debug("Stage %d: testing hcall: 0x%lx\n", stage,
-				 hcall->control);
-		else
-			pr_debug("Stage %d: finish\n", stage);
+		pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, hcall->control);
 
 		vcpu_run(vcpu);
 		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
@@ -649,16 +671,14 @@ static void guest_test_hcalls_access(void)
 			    run->exit_reason, exit_reason_str(run->exit_reason));
 
 		switch (get_ucall(vcpu, &uc)) {
-		case UCALL_SYNC:
-			TEST_ASSERT(uc.args[1] == 0,
-				    "Unexpected stage: %ld (0 expected)\n",
-				    uc.args[1]);
-			break;
 		case UCALL_ABORT:
 			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
 				  __FILE__, uc.args[1]);
 			return;
 		case UCALL_DONE:
+			break;
+		default:
+			TEST_FAIL("Unhandled ucall: %ld", uc.cmd);
 			return;
 		}
 
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/5] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
                   ` (2 preceding siblings ...)
  2022-06-08 22:45 ` [PATCH 3/5] KVM: selftests: Mostly fix comically broken Hyper-V Features test Sean Christopherson
@ 2022-06-08 22:45 ` Sean Christopherson
  2022-06-08 22:45 ` [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test Sean Christopherson
  2022-06-20 15:00 ` [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Paolo Bonzini
  5 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Use exception fixup to verify VMCALL/RDMSR/WRMSR fault as expected in the
Hyper-V Features test.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 .../selftests/kvm/x86_64/hyperv_features.c    | 117 +++++-------------
 1 file changed, 33 insertions(+), 84 deletions(-)

diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
index 5ec40422d72a..0de13ab38e8b 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
@@ -15,75 +15,20 @@
 
 #define LINUX_OS_ID ((u64)0x8100 << 48)
 
-extern unsigned char rdmsr_start;
-extern unsigned char rdmsr_end;
-
-static u64 do_rdmsr(u32 idx)
-{
-	u32 lo, hi;
-
-	asm volatile("rdmsr_start: rdmsr;"
-		     "rdmsr_end:"
-		     : "=a"(lo), "=c"(hi)
-		     : "c"(idx));
-
-	return (((u64) hi) << 32) | lo;
-}
-
-extern unsigned char wrmsr_start;
-extern unsigned char wrmsr_end;
-
-static void do_wrmsr(u32 idx, u64 val)
-{
-	u32 lo, hi;
-
-	lo = val;
-	hi = val >> 32;
-
-	asm volatile("wrmsr_start: wrmsr;"
-		     "wrmsr_end:"
-		     : : "a"(lo), "c"(idx), "d"(hi));
-}
-
-static int nr_gp;
-static int nr_ud;
-
-static inline u64 hypercall(u64 control, vm_vaddr_t input_address,
-			    vm_vaddr_t output_address)
-{
-	u64 hv_status;
-
-	asm volatile("mov %3, %%r8\n"
-		     "vmcall"
-		     : "=a" (hv_status),
-		       "+c" (control), "+d" (input_address)
-		     :  "r" (output_address)
-		     : "cc", "memory", "r8", "r9", "r10", "r11");
-
-	return hv_status;
-}
-
-static void guest_gp_handler(struct ex_regs *regs)
-{
-	unsigned char *rip = (unsigned char *)regs->rip;
-	bool r, w;
-
-	r = rip == &rdmsr_start;
-	w = rip == &wrmsr_start;
-	GUEST_ASSERT(r || w);
-
-	nr_gp++;
-
-	if (r)
-		regs->rip = (uint64_t)&rdmsr_end;
-	else
-		regs->rip = (uint64_t)&wrmsr_end;
-}
-
-static void guest_ud_handler(struct ex_regs *regs)
-{
-	nr_ud++;
-	regs->rip += 3;
+static inline uint8_t hypercall(u64 control, vm_vaddr_t input_address,
+				vm_vaddr_t output_address, uint64_t *hv_status)
+{
+	uint8_t vector;
+
+	/* Note both the hypercall and the "asm safe" clobber r9-r11. */
+	asm volatile("mov %[output_address], %%r8\n\t"
+		     KVM_ASM_SAFE("vmcall")
+		     : "=a" (*hv_status),
+		       "+c" (control), "+d" (input_address),
+		       KVM_ASM_SAFE_OUTPUTS(vector)
+		     : [output_address] "r"(output_address)
+		     : "cc", "memory", "r8", KVM_ASM_SAFE_CLOBBERS);
+	return vector;
 }
 
 struct msr_data {
@@ -101,31 +46,33 @@ struct hcall_data {
 
 static void guest_msr(struct msr_data *msr)
 {
+	uint64_t ignored;
+	uint8_t vector;
+
 	GUEST_ASSERT(msr->idx);
 
-	WRITE_ONCE(nr_gp, 0);
 	if (!msr->write)
-		do_rdmsr(msr->idx);
+		vector = rdmsr_safe(msr->idx, &ignored);
 	else
-		do_wrmsr(msr->idx, msr->write_val);
+		vector = wrmsr_safe(msr->idx, msr->write_val);
 
 	if (msr->available)
-		GUEST_ASSERT(READ_ONCE(nr_gp) == 0);
+		GUEST_ASSERT_2(!vector, msr->idx, vector);
 	else
-		GUEST_ASSERT(READ_ONCE(nr_gp) == 1);
+		GUEST_ASSERT_2(vector == GP_VECTOR, msr->idx, vector);
 	GUEST_DONE();
 }
 
 static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
 {
 	u64 res, input, output;
+	uint8_t vector;
 
 	GUEST_ASSERT(hcall->control);
 
 	wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID);
 	wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
 
-	nr_ud = 0;
 	if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) {
 		input = pgs_gpa;
 		output = pgs_gpa + 4096;
@@ -133,12 +80,14 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
 		input = output = 0;
 	}
 
-	res = hypercall(hcall->control, input, output);
+	vector = hypercall(hcall->control, input, output, &res);
 	if (hcall->ud_expected)
-		GUEST_ASSERT(nr_ud == 1);
+		GUEST_ASSERT_2(vector == UD_VECTOR, hcall->control, vector);
 	else
-		GUEST_ASSERT(res == hcall->expect);
+		GUEST_ASSERT_2(!vector, hcall->control, vector);
 
+	GUEST_ASSERT_2(!hcall->ud_expected || res == hcall->expect,
+			hcall->expect, res);
 	GUEST_DONE();
 }
 
@@ -190,7 +139,6 @@ static void guest_test_msrs_access(void)
 
 		vm_init_descriptor_tables(vm);
 		vcpu_init_descriptor_tables(vcpu);
-		vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler);
 
 		run = vcpu->run;
 
@@ -499,8 +447,9 @@ static void guest_test_msrs_access(void)
 
 		switch (get_ucall(vcpu, &uc)) {
 		case UCALL_ABORT:
-			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
-				  __FILE__, uc.args[1]);
+			TEST_FAIL("%s at %s:%ld, MSR = %lx, vector = %lx",
+				  (const char *)uc.args[0], __FILE__,
+				  uc.args[1], uc.args[2], uc.args[3]);
 			return;
 		case UCALL_DONE:
 			break;
@@ -531,7 +480,6 @@ static void guest_test_hcalls_access(void)
 
 		vm_init_descriptor_tables(vm);
 		vcpu_init_descriptor_tables(vcpu);
-		vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
 
 		/* Hypercall input/output */
 		hcall_page = vm_vaddr_alloc_pages(vm, 2);
@@ -672,8 +620,9 @@ static void guest_test_hcalls_access(void)
 
 		switch (get_ucall(vcpu, &uc)) {
 		case UCALL_ABORT:
-			TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0],
-				  __FILE__, uc.args[1]);
+			TEST_FAIL("%s at %s:%ld, arg1 = %lx, arg2 = %lx",
+				  (const char *)uc.args[0], __FILE__,
+				  uc.args[1], uc.args[2], uc.args[3]);
 			return;
 		case UCALL_DONE:
 			break;
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
                   ` (3 preceding siblings ...)
  2022-06-08 22:45 ` [PATCH 4/5] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests Sean Christopherson
@ 2022-06-08 22:45 ` Sean Christopherson
  2022-06-09  6:37   ` Yuan Yao
  2022-06-20 15:00 ` [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Paolo Bonzini
  5 siblings, 1 reply; 9+ messages in thread
From: Sean Christopherson @ 2022-06-08 22:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

Add a test to verify the "MONITOR/MWAIT never fault" quirk, and as a
bonus, also verify the related "MISC_ENABLES ignores ENABLE_MWAIT" quirk.

If the "never fault" quirk is enabled, MONITOR/MWAIT should always be
emulated as NOPs, even if they're reported as disabled in guest CPUID.
Use the MISC_ENABLES quirk to coerce KVM into toggling the MWAIT CPUID
enable, as KVM now disallows manually toggling CPUID bits after running
the vCPU.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/x86_64/monitor_mwait_test.c | 127 ++++++++++++++++++
 3 files changed, 129 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c

diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 0ab0e255d292..1a56522f009c 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -27,6 +27,7 @@
 /x86_64/hyperv_svm_test
 /x86_64/max_vcpuid_cap_test
 /x86_64/mmio_warning_test
+/x86_64/monitor_mwait_test
 /x86_64/platform_info_test
 /x86_64/pmu_event_filter_test
 /x86_64/set_boot_cpu_id
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 9a256c1f1bdf..bbbfdeb7ee9b 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -56,6 +56,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_svm_test
 TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test
 TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
 TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
+TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test
 TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
 TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test
 TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
new file mode 100644
index 000000000000..b9af8e29721e
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+
+enum monitor_mwait_testcases {
+	MWAIT_QUIRK_DISABLED = BIT(0),
+	MISC_ENABLES_QUIRK_DISABLED = BIT(1),
+	MWAIT_DISABLED = BIT(2),
+};
+
+static void guest_monitor_wait(int testcase)
+{
+	/*
+	 * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD,
+	 * in all other scenarios KVM should emulate them as nops.
+	 */
+	bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) &&
+			    (testcase & MWAIT_DISABLED);
+	u8 vector;
+
+	GUEST_SYNC(testcase);
+
+	vector = kvm_asm_safe("monitor");
+	if (fault_wanted)
+		GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
+	else
+		GUEST_ASSERT_2(!vector, testcase, vector);
+
+	vector = kvm_asm_safe("monitor");
+	if (fault_wanted)
+		GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
+	else
+		GUEST_ASSERT_2(!vector, testcase, vector);
+}
+
+static void guest_code(void)
+{
+	guest_monitor_wait(MWAIT_DISABLED);
+
+	guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
+
+	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);
+	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);
+
+	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
+	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);
+
+	GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+	uint64_t disabled_quirks;
+	struct kvm_vcpu *vcpu;
+	struct kvm_run *run;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	int testcase;
+
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);
+
+	run = vcpu->run;
+
+	vm_init_descriptor_tables(vm);
+	vcpu_init_descriptor_tables(vcpu);
+
+	while (1) {
+		vcpu_run(vcpu);
+
+		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+			    "Unexpected exit reason: %u (%s),\n",
+			    run->exit_reason,
+			    exit_reason_str(run->exit_reason));
+
+		switch (get_ucall(vcpu, &uc)) {
+		case UCALL_SYNC:
+			testcase = uc.args[1];
+			break;
+		case UCALL_ABORT:
+			TEST_FAIL("%s at %s:%ld, testcase = %lx, vector = %ld",
+				  (const char *)uc.args[0], __FILE__,
+				  uc.args[1], uc.args[2], uc.args[3]);
+			goto done;
+		case UCALL_DONE:
+			goto done;
+		default:
+			TEST_FAIL("Unknown ucall %lu", uc.cmd);
+			goto done;
+		}
+
+		disabled_quirks = 0;
+		if (testcase & MWAIT_QUIRK_DISABLED)
+			disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_FAULTS;
+		if (testcase & MISC_ENABLES_QUIRK_DISABLED)
+			disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT;
+		vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks);
+
+		/*
+		 * If the MISC_ENABLES quirk (KVM neglects to update CPUID to
+		 * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT
+		 * bit in MISC_ENABLES accordingly.  If the quirk is enabled,
+		 * the only valid configuration is MWAIT disabled, as CPUID
+		 * can't be manually changed after running the vCPU.
+		 */
+		if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) {
+			TEST_ASSERT(testcase & MWAIT_DISABLED,
+				    "Can't toggle CPUID features after running vCPU");
+			continue;
+		}
+
+		vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,
+			     (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);
+	}
+
+done:
+	kvm_vm_free(vm);
+	return 0;
+}
-- 
2.36.1.255.ge46751e96f-goog


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test
  2022-06-08 22:45 ` [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test Sean Christopherson
@ 2022-06-09  6:37   ` Yuan Yao
  2022-06-09 13:55     ` Sean Christopherson
  0 siblings, 1 reply; 9+ messages in thread
From: Yuan Yao @ 2022-06-09  6:37 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

On Wed, Jun 08, 2022 at 10:45:16PM +0000, Sean Christopherson wrote:
> Add a test to verify the "MONITOR/MWAIT never fault" quirk, and as a
> bonus, also verify the related "MISC_ENABLES ignores ENABLE_MWAIT" quirk.
>
> If the "never fault" quirk is enabled, MONITOR/MWAIT should always be
> emulated as NOPs, even if they're reported as disabled in guest CPUID.
> Use the MISC_ENABLES quirk to coerce KVM into toggling the MWAIT CPUID
> enable, as KVM now disallows manually toggling CPUID bits after running
> the vCPU.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>  tools/testing/selftests/kvm/.gitignore        |   1 +
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../selftests/kvm/x86_64/monitor_mwait_test.c | 127 ++++++++++++++++++
>  3 files changed, 129 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
>
> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> index 0ab0e255d292..1a56522f009c 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -27,6 +27,7 @@
>  /x86_64/hyperv_svm_test
>  /x86_64/max_vcpuid_cap_test
>  /x86_64/mmio_warning_test
> +/x86_64/monitor_mwait_test
>  /x86_64/platform_info_test
>  /x86_64/pmu_event_filter_test
>  /x86_64/set_boot_cpu_id
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index 9a256c1f1bdf..bbbfdeb7ee9b 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -56,6 +56,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_svm_test
>  TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test
>  TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
>  TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
> +TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test
>  TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
>  TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test
>  TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
> diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
> new file mode 100644
> index 000000000000..b9af8e29721e
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +
> +#include "kvm_util.h"
> +#include "processor.h"
> +
> +enum monitor_mwait_testcases {
> +	MWAIT_QUIRK_DISABLED = BIT(0),
> +	MISC_ENABLES_QUIRK_DISABLED = BIT(1),
> +	MWAIT_DISABLED = BIT(2),
> +};
> +
> +static void guest_monitor_wait(int testcase)
> +{
> +	/*
> +	 * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD,
> +	 * in all other scenarios KVM should emulate them as nops.
> +	 */
> +	bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) &&
> +			    (testcase & MWAIT_DISABLED);
> +	u8 vector;
> +
> +	GUEST_SYNC(testcase);
> +
> +	vector = kvm_asm_safe("monitor");
> +	if (fault_wanted)
> +		GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
> +	else
> +		GUEST_ASSERT_2(!vector, testcase, vector);
> +
> +	vector = kvm_asm_safe("monitor");

emmm... should one of the "monitor" be "mwait" ?

> +	if (fault_wanted)
> +		GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
> +	else
> +		GUEST_ASSERT_2(!vector, testcase, vector);
> +}
> +
> +static void guest_code(void)
> +{
> +	guest_monitor_wait(MWAIT_DISABLED);
> +
> +	guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
> +
> +	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED);
> +	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED);
> +
> +	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED);
> +	guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED);
> +
> +	GUEST_DONE();
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	uint64_t disabled_quirks;
> +	struct kvm_vcpu *vcpu;
> +	struct kvm_run *run;
> +	struct kvm_vm *vm;
> +	struct ucall uc;
> +	int testcase;
> +
> +	TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
> +
> +	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +	vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT);
> +
> +	run = vcpu->run;
> +
> +	vm_init_descriptor_tables(vm);
> +	vcpu_init_descriptor_tables(vcpu);
> +
> +	while (1) {
> +		vcpu_run(vcpu);
> +
> +		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
> +			    "Unexpected exit reason: %u (%s),\n",
> +			    run->exit_reason,
> +			    exit_reason_str(run->exit_reason));
> +
> +		switch (get_ucall(vcpu, &uc)) {
> +		case UCALL_SYNC:
> +			testcase = uc.args[1];
> +			break;
> +		case UCALL_ABORT:
> +			TEST_FAIL("%s at %s:%ld, testcase = %lx, vector = %ld",
> +				  (const char *)uc.args[0], __FILE__,
> +				  uc.args[1], uc.args[2], uc.args[3]);
> +			goto done;
> +		case UCALL_DONE:
> +			goto done;
> +		default:
> +			TEST_FAIL("Unknown ucall %lu", uc.cmd);
> +			goto done;
> +		}
> +
> +		disabled_quirks = 0;
> +		if (testcase & MWAIT_QUIRK_DISABLED)
> +			disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_FAULTS;
> +		if (testcase & MISC_ENABLES_QUIRK_DISABLED)
> +			disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT;
> +		vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks);
> +
> +		/*
> +		 * If the MISC_ENABLES quirk (KVM neglects to update CPUID to
> +		 * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT
> +		 * bit in MISC_ENABLES accordingly.  If the quirk is enabled,
> +		 * the only valid configuration is MWAIT disabled, as CPUID
> +		 * can't be manually changed after running the vCPU.
> +		 */
> +		if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) {
> +			TEST_ASSERT(testcase & MWAIT_DISABLED,
> +				    "Can't toggle CPUID features after running vCPU");
> +			continue;
> +		}
> +
> +		vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE,
> +			     (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT);
> +	}
> +
> +done:
> +	kvm_vm_free(vm);
> +	return 0;
> +}
> --
> 2.36.1.255.ge46751e96f-goog
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test
  2022-06-09  6:37   ` Yuan Yao
@ 2022-06-09 13:55     ` Sean Christopherson
  0 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2022-06-09 13:55 UTC (permalink / raw)
  To: Yuan Yao
  Cc: Paolo Bonzini, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel

On Thu, Jun 09, 2022, Yuan Yao wrote:
> On Wed, Jun 08, 2022 at 10:45:16PM +0000, Sean Christopherson wrote:
> > +static void guest_monitor_wait(int testcase)
> > +{
> > +	/*
> > +	 * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD,
> > +	 * in all other scenarios KVM should emulate them as nops.
> > +	 */
> > +	bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) &&
> > +			    (testcase & MWAIT_DISABLED);
> > +	u8 vector;
> > +
> > +	GUEST_SYNC(testcase);
> > +
> > +	vector = kvm_asm_safe("monitor");
> > +	if (fault_wanted)
> > +		GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector);
> > +	else
> > +		GUEST_ASSERT_2(!vector, testcase, vector);
> > +
> > +	vector = kvm_asm_safe("monitor");
> 
> emmm... should one of the "monitor" be "mwait" ?

/facepalm

Thanks for catching my copy+paste fail!

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior
  2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
                   ` (4 preceding siblings ...)
  2022-06-08 22:45 ` [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test Sean Christopherson
@ 2022-06-20 15:00 ` Paolo Bonzini
  5 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2022-06-20 15:00 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, kvm,
	linux-kernel

Queued, thanks.

Paolo



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-06-20 15:16 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 22:45 [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Sean Christopherson
2022-06-08 22:45 ` [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior Sean Christopherson
2022-06-08 22:45 ` [PATCH 2/5] KVM: selftests: Add x86-64 support for exception fixup Sean Christopherson
2022-06-08 22:45 ` [PATCH 3/5] KVM: selftests: Mostly fix comically broken Hyper-V Features test Sean Christopherson
2022-06-08 22:45 ` [PATCH 4/5] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests Sean Christopherson
2022-06-08 22:45 ` [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test Sean Christopherson
2022-06-09  6:37   ` Yuan Yao
2022-06-09 13:55     ` Sean Christopherson
2022-06-20 15:00 ` [PATCH 0/5] KVM: x86: Quirk "MWAIT never faults" behavior Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.