diff mbox

kvm_pv_unhalt and kernel_irqchip=off

Message ID 20160810205830.GB27257@potion (mailing list archive)
State New, archived
Headers show

Commit Message

Radim Krčmář Aug. 10, 2016, 8:58 p.m. UTC
2016-08-10 21:04+0200, Radim Krčmář:
>> Related question: is there any kvm-unit-test test for
>> kvm_pv_unhalt?
> 
> Not that I know of, thanks for the request.

I attached a simple test below.  It will likely need some modifications
after the bug is fixed in QEMU and/or KVM.

For a fix in KVM, I used the solution from another feature that doesn't
work with irqchip=off, x2APIC.
Jokes aside, we can fix them both because SET_CPUID cannot be called
after CREATE_IRQCHIP.  I'll do so tomorrow.

---8<---
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index ee7f180237b1..f33c680e5dbf 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -402,6 +402,11 @@  static inline void safe_halt(void)
 	asm volatile("sti; hlt");
 }
 
+static inline void cpu_relax(void)
+{
+	asm volatile ("rep; nop");
+}
+
 static inline u32 read_pkru(void)
 {
     unsigned int eax, edx;
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 356d879a986b..6a3bbc86df68 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -45,6 +45,7 @@  tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
                $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
                $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \
+               $(TEST_DIR)/pv_unhalt.flat \
 
 ifdef API
 tests-common += api/api-sample
diff --git a/x86/pv_unhalt.c b/x86/pv_unhalt.c
new file mode 100644
index 000000000000..d717e309eab0
--- /dev/null
+++ b/x86/pv_unhalt.c
@@ -0,0 +1,73 @@ 
+#include "libcflat.h"
+#include "vm.h"
+#include "desc.h"
+#include "smp.h"
+
+/* Intel and AMD hypercalls should be interchangeable. */
+#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
+
+#define KVM_HC_KICK_CPU			5
+
+#define KVM_CPUID_FEATURES	0x40000001
+#define KVM_FEATURE_PV_UNHALT	(1 << 7)
+
+static volatile bool pv_unhalt_works;
+
+static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
+				  unsigned long p2)
+{
+	long ret;
+	asm volatile(KVM_HYPERCALL
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1), "c"(p2)
+		     : "memory");
+	return ret;
+}
+
+static void halt(void * nothing)
+{
+	asm volatile("cli; hlt; sti" ::: "memory");
+
+	pv_unhalt_works = true;
+}
+
+static void test_pv_unhalt(void)
+{
+	unsigned long delay;
+
+	if (cpu_count() < 2) {
+		report_skip("pv unhalt");
+		return;
+	}
+
+	/* XXX: KVM_CPUID_FEATURES can have a different base offset */
+	if (!(cpuid(KVM_CPUID_FEATURES).a & KVM_FEATURE_PV_UNHALT)) {
+		/* TODO: use argv to decide whether the presence of pv_unhalt
+		 * is a skip or pass? */
+		report("pv unhalt", 1);
+		return;
+	}
+
+	on_cpu_async(1, halt, 0);
+	/* we need a small delay because CPU1 can't notify that it halted */
+	for (delay = 1<<28; delay; delay--)
+		cpu_relax();
+
+	kvm_hypercall2(KVM_HC_KICK_CPU, 0, 1);
+
+	/* TODO: sane delay loops (ignoring pv_unhalt_works is fine) */
+	for (delay = 1<<28; delay && !pv_unhalt_works; delay--)
+		cpu_relax();
+
+	report("pv unhalt", pv_unhalt_works);
+}
+
+int main(int ac, char **av)
+{
+	setup_vm();
+	smp_init();
+
+	test_pv_unhalt();
+
+	return report_summary();
+}
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 60747cfca94e..6fe688d01357 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -197,3 +197,13 @@  extra_params = -cpu kvm64,hv_synic -device hyperv-testdev
 file = hyperv_stimer.flat
 smp = 2
 extra_params = -cpu kvm64,hv_time,hv_synic,hv_stimer -device hyperv-testdev
+
+[pv_unhalt]
+file = pv_unhalt.flat
+smp = 2
+extra_params = -cpu kvm64,+kvm_pv_unhalt
+
+[pv_unhalt_irqchip_off]
+file = pv_unhalt.flat
+smp = 2
+extra_params = -cpu kvm64,+kvm_pv_unhalt -machine kernel_irqchip=off