1 // SPDX-License-Identifier: GPL-2.0
3 * Tests for MSR_IA32_TSC and MSR_IA32_TSC_ADJUST.
5 * Copyright (C) 2020, Red Hat, Inc.
10 #include "processor.h"
12 #define UNITY (1ull << 30)
13 #define HOST_ADJUST (UNITY * 64)
14 #define GUEST_STEP (UNITY * 4)
15 #define ROUND(x) ((x + UNITY / 2) & -UNITY)
16 #define rounded_rdmsr(x) ROUND(rdmsr(x))
17 #define rounded_host_rdmsr(x) ROUND(vcpu_get_msr(vcpu, x))
19 static void guest_code(void)
23 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), val
);
24 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
26 /* Guest: writes to MSR_IA32_TSC affect both MSRs. */
27 val
= 1ull * GUEST_STEP
;
28 wrmsr(MSR_IA32_TSC
, val
);
29 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), val
);
30 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
32 /* Guest: writes to MSR_IA32_TSC_ADJUST affect both MSRs. */
34 val
= 2ull * GUEST_STEP
;
35 wrmsr(MSR_IA32_TSC_ADJUST
, val
);
36 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), val
);
37 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
39 /* Host: setting the TSC offset. */
41 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
42 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
45 * Guest: writes to MSR_IA32_TSC_ADJUST do not destroy the
46 * host-side offset and affect both MSRs.
49 val
= 3ull * GUEST_STEP
;
50 wrmsr(MSR_IA32_TSC_ADJUST
, val
);
51 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
52 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
55 * Guest: writes to MSR_IA32_TSC affect both MSRs, so the host-side
56 * offset is now visible in MSR_IA32_TSC_ADJUST.
59 val
= 4ull * GUEST_STEP
;
60 wrmsr(MSR_IA32_TSC
, val
);
61 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC
), val
);
62 GUEST_ASSERT_EQ(rounded_rdmsr(MSR_IA32_TSC_ADJUST
), val
- HOST_ADJUST
);
67 static void run_vcpu(struct kvm_vcpu
*vcpu
, int stage
)
73 switch (get_ucall(vcpu
, &uc
)) {
75 if (!strcmp((const char *)uc
.args
[0], "hello") &&
76 uc
.args
[1] == stage
+ 1)
77 ksft_test_result_pass("stage %d passed\n", stage
+ 1);
79 ksft_test_result_fail(
80 "stage %d: Unexpected register values vmexit, got %lx",
81 stage
+ 1, (ulong
)uc
.args
[1]);
84 ksft_test_result_pass("stage %d passed\n", stage
+ 1);
87 REPORT_GUEST_ASSERT(uc
);
89 TEST_ASSERT(false, "Unexpected exit: %s",
90 exit_reason_str(vcpu
->run
->exit_reason
));
96 struct kvm_vcpu
*vcpu
;
103 vm
= vm_create_with_one_vcpu(&vcpu
, guest_code
);
106 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), val
);
107 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
109 /* Guest: writes to MSR_IA32_TSC affect both MSRs. */
111 val
= 1ull * GUEST_STEP
;
112 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), val
);
113 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
115 /* Guest: writes to MSR_IA32_TSC_ADJUST affect both MSRs. */
117 val
= 2ull * GUEST_STEP
;
118 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), val
);
119 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
122 * Host: writes to MSR_IA32_TSC set the host-side offset
123 * and therefore do not change MSR_IA32_TSC_ADJUST.
125 vcpu_set_msr(vcpu
, MSR_IA32_TSC
, HOST_ADJUST
+ val
);
126 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
127 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
130 /* Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC. */
131 vcpu_set_msr(vcpu
, MSR_IA32_TSC_ADJUST
, UNITY
* 123456);
132 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
133 TEST_ASSERT_EQ(vcpu_get_msr(vcpu
, MSR_IA32_TSC_ADJUST
), UNITY
* 123456);
135 /* Restore previous value. */
136 vcpu_set_msr(vcpu
, MSR_IA32_TSC_ADJUST
, val
);
137 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
138 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
141 * Guest: writes to MSR_IA32_TSC_ADJUST do not destroy the
142 * host-side offset and affect both MSRs.
145 val
= 3ull * GUEST_STEP
;
146 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), HOST_ADJUST
+ val
);
147 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
);
150 * Guest: writes to MSR_IA32_TSC affect both MSRs, so the host-side
151 * offset is now visible in MSR_IA32_TSC_ADJUST.
154 val
= 4ull * GUEST_STEP
;
155 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC
), val
);
156 TEST_ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST
), val
- HOST_ADJUST
);
160 ksft_finished(); /* Print results and exit() accordingly */