Run the test once with quirk enabled and once disabled, and adjust the expected values accordingly.
Signed-off-by: Maxim Levitsky mlevitsk@redhat.com --- .../selftests/kvm/x86_64/tsc_msrs_test.c | 79 ++++++++++++++++--- 1 file changed, 69 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index e357d8e222d47..3900c543a7ee1 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -79,8 +79,6 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) { struct ucall uc;
- vcpu_args_set(vm, vcpuid, 1, vcpuid); - vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL);
switch (get_ucall(vm, vcpuid, &uc)) { @@ -101,7 +99,7 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) } }
-int main(void) +void run_test(bool quirk_disabled) { struct kvm_vm *vm; uint64_t val; @@ -109,6 +107,14 @@ int main(void) vm = vm_create_default(VCPU_ID, 0, guest_code);
val = 0; + if (quirk_disabled) { + struct kvm_enable_cap cap = { + .cap = KVM_CAP_DISABLE_QUIRKS, + .args[0] = KVM_X86_QUIRK_TSC_HOST_ACCESS, + }; + vm_enable_cap(vm, &cap); + } + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val);
@@ -124,20 +130,67 @@ int main(void) ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val);
- /* - * Host: writes to MSR_IA32_TSC set the host-side offset - * and therefore do not change MSR_IA32_TSC_ADJUST. - */ - vcpu_set_msr(vm, 0, MSR_IA32_TSC, HOST_ADJUST + val); + if (quirk_disabled) { + struct kvm_tsc_state state = { + .tsc = HOST_ADJUST + val, + .flags = 0 + }; + vcpu_ioctl(vm, VCPU_ID, KVM_SET_TSC_STATE, &state); + } else { + /* + * Host: writes to MSR_IA32_TSC set the host-side offset + * and therefore do not change MSR_IA32_TSC_ADJUST + */ + vcpu_set_msr(vm, 0, MSR_IA32_TSC, HOST_ADJUST + val); + } + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + + if (quirk_disabled) { + /* + * Host: writes to MSR_IA32_TSC work like in the guest + * when quirk is disabled + */ + vcpu_set_msr(vm, 0, MSR_IA32_TSC, val); + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val - HOST_ADJUST); + + /* Restore the value */ + vcpu_set_msr(vm, 0, MSR_IA32_TSC, HOST_ADJUST + val); + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); + } + run_vcpu(vm, VCPU_ID, 3);
- /* Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC. */ + /* + * Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC, + * (unless the quirk is disabled) + */ vcpu_set_msr(vm, 0, MSR_IA32_TSC_ADJUST, UNITY * 123456); - ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), + quirk_disabled ? UNITY * 123456 + HOST_ADJUST : HOST_ADJUST + val); ASSERT_EQ(vcpu_get_msr(vm, 0, MSR_IA32_TSC_ADJUST), UNITY * 123456);
+ if (quirk_disabled) { + /* + * Host: writes via KVM_SET_TSC_STATE + * to MSR_IA32_TSC and MSR_IA32_TSC_ADJUST can be done + * independently + */ + struct kvm_tsc_state state = { + .tsc = UNITY * 42, + .tsc_adjust = UNITY * 42 - HOST_ADJUST, + .flags = KVM_TSC_STATE_TSC_ADJUST_VALID + }; + + vcpu_ioctl(vm, VCPU_ID, KVM_SET_TSC_STATE, &state); + + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), UNITY * 42); + ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), + UNITY * 42 - HOST_ADJUST); + } + /* Restore previous value. */ vcpu_set_msr(vm, 0, MSR_IA32_TSC_ADJUST, val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); @@ -162,6 +215,12 @@ int main(void) ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val - HOST_ADJUST);
kvm_vm_free(vm); +} +
+int main(void) +{ + run_test(false); + run_test(true); return 0; }