diff options
author | KarimAllah Ahmed <karahmed@amazon.de> | 2018-04-13 23:10:52 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2018-04-16 11:50:11 -0400 |
commit | e79f245ddec17bbd89d73cd0169dba4be46c9b55 (patch) | |
tree | 0cf1274bfc8df0b80aeb1908a052e707fe9082c0 /arch/x86/kvm/svm.c | |
parent | 4e1acd7b31a03f24cc6108d37d005e6b1d48c5d3 (diff) |
X86/KVM: Properly update 'tsc_offset' to represent the running guest
Update 'tsc_offset' on vmentry/vmexit of L2 guests to ensure that it always
captures the TSC_OFFSET of the running guest whether it is the L1 or L2
guest.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Reviewed-by: Jim Mattson <jmattson@google.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: KarimAllah Ahmed <karahmed@amazon.de>
[AMD changes, fix update_ia32_tsc_adjust_msr. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index b3ebc8ad6891..e77a536d0b7c 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -1424,12 +1424,23 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) | |||
1424 | seg->base = 0; | 1424 | seg->base = 0; |
1425 | } | 1425 | } |
1426 | 1426 | ||
1427 | static u64 svm_read_l1_tsc_offset(struct kvm_vcpu *vcpu) | ||
1428 | { | ||
1429 | struct vcpu_svm *svm = to_svm(vcpu); | ||
1430 | |||
1431 | if (is_guest_mode(vcpu)) | ||
1432 | return svm->nested.hsave->control.tsc_offset; | ||
1433 | |||
1434 | return vcpu->arch.tsc_offset; | ||
1435 | } | ||
1436 | |||
1427 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) | 1437 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) |
1428 | { | 1438 | { |
1429 | struct vcpu_svm *svm = to_svm(vcpu); | 1439 | struct vcpu_svm *svm = to_svm(vcpu); |
1430 | u64 g_tsc_offset = 0; | 1440 | u64 g_tsc_offset = 0; |
1431 | 1441 | ||
1432 | if (is_guest_mode(vcpu)) { | 1442 | if (is_guest_mode(vcpu)) { |
1443 | /* Write L1's TSC offset. */ | ||
1433 | g_tsc_offset = svm->vmcb->control.tsc_offset - | 1444 | g_tsc_offset = svm->vmcb->control.tsc_offset - |
1434 | svm->nested.hsave->control.tsc_offset; | 1445 | svm->nested.hsave->control.tsc_offset; |
1435 | svm->nested.hsave->control.tsc_offset = offset; | 1446 | svm->nested.hsave->control.tsc_offset = offset; |
@@ -3323,6 +3334,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) | |||
3323 | /* Restore the original control entries */ | 3334 | /* Restore the original control entries */ |
3324 | copy_vmcb_control_area(vmcb, hsave); | 3335 | copy_vmcb_control_area(vmcb, hsave); |
3325 | 3336 | ||
3337 | svm->vcpu.arch.tsc_offset = svm->vmcb->control.tsc_offset; | ||
3326 | kvm_clear_exception_queue(&svm->vcpu); | 3338 | kvm_clear_exception_queue(&svm->vcpu); |
3327 | kvm_clear_interrupt_queue(&svm->vcpu); | 3339 | kvm_clear_interrupt_queue(&svm->vcpu); |
3328 | 3340 | ||
@@ -3483,10 +3495,12 @@ static void enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb_gpa, | |||
3483 | /* We don't want to see VMMCALLs from a nested guest */ | 3495 | /* We don't want to see VMMCALLs from a nested guest */ |
3484 | clr_intercept(svm, INTERCEPT_VMMCALL); | 3496 | clr_intercept(svm, INTERCEPT_VMMCALL); |
3485 | 3497 | ||
3498 | svm->vcpu.arch.tsc_offset += nested_vmcb->control.tsc_offset; | ||
3499 | svm->vmcb->control.tsc_offset = svm->vcpu.arch.tsc_offset; | ||
3500 | |||
3486 | svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext; | 3501 | svm->vmcb->control.virt_ext = nested_vmcb->control.virt_ext; |
3487 | svm->vmcb->control.int_vector = nested_vmcb->control.int_vector; | 3502 | svm->vmcb->control.int_vector = nested_vmcb->control.int_vector; |
3488 | svm->vmcb->control.int_state = nested_vmcb->control.int_state; | 3503 | svm->vmcb->control.int_state = nested_vmcb->control.int_state; |
3489 | svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset; | ||
3490 | svm->vmcb->control.event_inj = nested_vmcb->control.event_inj; | 3504 | svm->vmcb->control.event_inj = nested_vmcb->control.event_inj; |
3491 | svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err; | 3505 | svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err; |
3492 | 3506 | ||
@@ -7102,6 +7116,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { | |||
7102 | 7116 | ||
7103 | .has_wbinvd_exit = svm_has_wbinvd_exit, | 7117 | .has_wbinvd_exit = svm_has_wbinvd_exit, |
7104 | 7118 | ||
7119 | .read_l1_tsc_offset = svm_read_l1_tsc_offset, | ||
7105 | .write_tsc_offset = svm_write_tsc_offset, | 7120 | .write_tsc_offset = svm_write_tsc_offset, |
7106 | 7121 | ||
7107 | .set_tdp_cr3 = set_tdp_cr3, | 7122 | .set_tdp_cr3 = set_tdp_cr3, |