diff mbox

[kvm-unit-tests] x86: svm: add test for MSR_IA32_TSC_ADJUST

Message ID 20180413155336.22947-1-pbonzini@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Paolo Bonzini April 13, 2018, 3:53 p.m. UTC
The test checks the behavior of the MSR between L1 and L2.  In
particular, the value must be preserved across entry and exit,
even in presence of a TSC offset in the VMCB.

Based on a VMX test by Ken Hofsass.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 x86/svm.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
diff mbox

Patch

diff --git a/x86/svm.c b/x86/svm.c
index 162632c..2350911 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -877,6 +877,46 @@  static bool npt_rw_l1mmio_check(struct test *test)
            && (test->vmcb->control.exit_info_1 == 0x100000007ULL);
 }
 
+#define TSC_ADJUST_VALUE    (1ll << 32)
+#define TSC_OFFSET_VALUE    (-1ll << 48)
+static bool ok;
+
+static void tsc_adjust_prepare(struct test *test)
+{
+    default_prepare(test);
+    test->vmcb->control.tsc_offset = TSC_OFFSET_VALUE;
+
+    wrmsr(MSR_IA32_TSC_ADJUST, -TSC_ADJUST_VALUE);
+    int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST);
+    ok = adjust == -TSC_ADJUST_VALUE;
+}
+
+static void tsc_adjust_test(struct test *test)
+{
+    int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST);
+    ok &= adjust == -TSC_ADJUST_VALUE;
+
+    uint64_t l1_tsc = rdtsc() - TSC_OFFSET_VALUE;
+    wrmsr(MSR_IA32_TSC, l1_tsc - TSC_ADJUST_VALUE);
+
+    adjust = rdmsr(MSR_IA32_TSC_ADJUST);
+    ok &= adjust <= -2 * TSC_ADJUST_VALUE;
+
+    uint64_t l1_tsc_end = rdtsc() - TSC_OFFSET_VALUE;
+    ok &= (l1_tsc_end + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE;
+
+    uint64_t l1_tsc_msr = rdmsr(MSR_IA32_TSC) - TSC_OFFSET_VALUE;
+    ok &= (l1_tsc_msr + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE;
+}
+
+static bool tsc_adjust_check(struct test *test)
+{
+    int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST);
+
+    wrmsr(MSR_IA32_TSC_ADJUST, 0);
+    return ok && adjust <= -2 * TSC_ADJUST_VALUE;
+}
+
 static void latency_prepare(struct test *test)
 {
     default_prepare(test);
@@ -1048,6 +1088,8 @@  static struct test tests[] = {
 	    default_finished, npt_l1mmio_check },
     { "npt_rw_l1mmio", npt_supported, npt_rw_l1mmio_prepare, npt_rw_l1mmio_test,
 	    default_finished, npt_rw_l1mmio_check },
+    { "tsc_adjust", default_supported, tsc_adjust_prepare, tsc_adjust_test,
+       default_finished, tsc_adjust_check },
     { "latency_run_exit", default_supported, latency_prepare, latency_test,
       latency_finished, latency_check },
     { "latency_svm_insn", default_supported, lat_svm_insn_prepare, null_test,