Added x86/tsc_adjust.c and updated x86/vmexit.c to include timing tests for reading and writing the emulated IA32_TSC_ADJUST msr. Signed-off-by: Will Auld <will.auld@xxxxxxxxx> --- config-x86-common.mak | 5 ++++- x86/tsc_adjust.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ x86/vmexit.c | 13 +++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 x86/tsc_adjust.c diff --git a/config-x86-common.mak b/config-x86-common.mak index c76cd11..8f909f7 100644 --- a/config-x86-common.mak +++ b/config-x86-common.mak @@ -34,7 +34,8 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \ $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \ $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/eventinj.flat \ - $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat $(TEST_DIR)/asyncpf.flat + $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ + $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat ifdef API tests-common += api/api-sample @@ -64,6 +65,8 @@ $(TEST_DIR)/port80.elf: $(cstart.o) $(TEST_DIR)/port80.o $(TEST_DIR)/tsc.elf: $(cstart.o) $(TEST_DIR)/tsc.o +$(TEST_DIR)/tsc_adjust.elf: $(cstart.o) $(TEST_DIR)/tsc_adjust.o + $(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o diff --git a/x86/tsc_adjust.c b/x86/tsc_adjust.c new file mode 100644 index 0000000..05cc5d9 --- /dev/null +++ b/x86/tsc_adjust.c @@ -0,0 +1,60 @@ +#include "libcflat.h" +#include "processor.h" + +#define IA32_TSC_ADJUST 0x3b + +int main() +{ + u64 t1, t2, t3, t4, t5; + u64 est_delta_time; + bool pass = true; + + if (cpuid(7).b & (1 << 1)) { // IA32_TSC_ADJUST Feature is enabled? + if ( rdmsr(IA32_TSC_ADJUST) != 0x0) { + printf("failure: IA32_TSC_ADJUST msr was incorrectly" + " initialized\n"); + pass = false; + } + t3 = 100000000000ull; + t1 = rdtsc(); + wrmsr(IA32_TSC_ADJUST, t3); + t2 = rdtsc(); + if (rdmsr(IA32_TSC_ADJUST) != t3) { + printf("failure: IA32_TSC_ADJUST msr read / write" + " incorrect\n"); + pass = false; + } + if (t2 - t1 < t3) { + printf("failure: TSC did not adjust for IA32_TSC_ADJUST" + " value\n"); + pass = false; + } + t3 = 0x0; + wrmsr(IA32_TSC_ADJUST, t3); + if (rdmsr(IA32_TSC_ADJUST) != t3) { + printf("failure: IA32_TSC_ADJUST msr read / write" + " incorrect\n"); + pass = false; + } + t4 = 100000000000ull; + t1 = rdtsc(); + wrtsc(t4); + t2 = rdtsc(); + t5 = rdmsr(IA32_TSC_ADJUST); + // est of time between reading tsc and writing tsc, + // (based on IA32_TSC_ADJUST msr value) should be small + est_delta_time = t4 - t5 - t1; + if (est_delta_time > 2 * (t2 - t4)) { + // arbitray 2x latency (wrtsc->rdtsc) threshold + printf("failure: IA32_TSC_ADJUST msr incorrectly" + " adjusted on tsc write\n"); + pass = false; + } + if (pass) printf("success: IA32_TSC_ADJUST enabled and" + " working correctly\n"); + } + else { + printf("success: IA32_TSC_ADJUST feature not enabled\n"); + } + return pass?0:1; +} diff --git a/x86/vmexit.c b/x86/vmexit.c index ad8ab55..99ff964 100644 --- a/x86/vmexit.c +++ b/x86/vmexit.c @@ -34,6 +34,7 @@ static void vmcall(void) asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); } +#define MSR_TSC_ADJUST 0x3b #define MSR_EFER 0xc0000080 #define EFER_NX_MASK (1ull << 11) @@ -103,6 +104,16 @@ static void ple_round_robin(void) ++counters[you].n1; } +static void rd_tsc_adjust_msr(void) +{ + rdmsr(MSR_TSC_ADJUST); +} + +static void wr_tsc_adjust_msr(void) +{ + wrmsr(MSR_TSC_ADJUST, 0x0); +} + static struct test { void (*func)(void); const char *name; @@ -119,6 +130,8 @@ static struct test { { ipi, "ipi", is_smp, .parallel = 0, }, { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, { ple_round_robin, "ple-round-robin", .parallel = 1 }, + { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 }, + { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 }, }; unsigned iterations; -- 1.8.0.rc0 -- 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