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<--- 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 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html