On 08/11/18 10:51, Liran Alon wrote: > From: Leonid Shatz <leonid.shatz@xxxxxxxxxx> > > Since commit e79f245ddec1 ("X86/KVM: Properly update 'tsc_offset' to > represent the running guest"), vcpu->arch.tsc_offset meaning was > changed to always reflect the tsc_offset value set on active VMCS. > Regardless if vCPU is currently running L1 or L2. > > However, above mentioned commit failed to also change > kvm_vcpu_write_tsc_offset() to set vcpu->arch.tsc_offset correctly. > This is because vmx_write_tsc_offset() could set the tsc_offset value > in active VMCS to given offset parameter *plus vmcs12->tsc_offset*. > However, kvm_vcpu_write_tsc_offset() just sets vcpu->arch.tsc_offset > to given offset parameter. Without taking into account the possible > addition of vmcs12->tsc_offset. (Same is true for SVM case). > > Fix this issue by changing kvm_x86_ops->write_tsc_offset() to return > actually set tsc_offset in active VMCS and modify > kvm_vcpu_write_tsc_offset() to set returned value in > vcpu->arch.tsc_offset. > In addition, rename write_tsc_offset() argument to clearly indicate > it specifies a L1 TSC offset. > > Fixes: e79f245ddec1 ("X86/KVM: Properly update 'tsc_offset' to represent the running guest") > > Reviewed-by: Liran Alon <liran.alon@xxxxxxxxxx> > Reviewed-by: Mihai Carabas <mihai.carabas@xxxxxxxxxx> > Reviewed-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx> > Signed-off-by: Leonid Shatz <leonid.shatz@xxxxxxxxxx> > --- > arch/x86/include/asm/kvm_host.h | 6 +++++- > arch/x86/kvm/svm.c | 9 +++++---- > arch/x86/kvm/vmx.c | 21 +++++++++------------ > arch/x86/kvm/x86.c | 8 ++++---- > 4 files changed, 23 insertions(+), 21 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 55e51ff7e421..cc9df79b1016 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1094,7 +1094,11 @@ struct kvm_x86_ops { > bool (*has_wbinvd_exit)(void); > > u64 (*read_l1_tsc_offset)(struct kvm_vcpu *vcpu); > - void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset); > + /* > + * Updates active guest TSC offset based on given L1 TSC offset > + * and returns actual TSC offset set for the active guest > + */ > + u64 (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 l1_offset); > > void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2); > > diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c > index 0e21ccc46792..842d4bb053d1 100644 > --- a/arch/x86/kvm/svm.c > +++ b/arch/x86/kvm/svm.c > @@ -1446,7 +1446,7 @@ static u64 svm_read_l1_tsc_offset(struct kvm_vcpu *vcpu) > return vcpu->arch.tsc_offset; > } > > -static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > +static u64 svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) > { > struct vcpu_svm *svm = to_svm(vcpu); > u64 g_tsc_offset = 0; > @@ -1455,15 +1455,16 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > /* Write L1's TSC offset. */ > g_tsc_offset = svm->vmcb->control.tsc_offset - > svm->nested.hsave->control.tsc_offset; > - svm->nested.hsave->control.tsc_offset = offset; > + svm->nested.hsave->control.tsc_offset = l1_offset; > } else > trace_kvm_write_tsc_offset(vcpu->vcpu_id, > svm->vmcb->control.tsc_offset, > - offset); > + l1_offset); > > - svm->vmcb->control.tsc_offset = offset + g_tsc_offset; > + svm->vmcb->control.tsc_offset = l1_offset + g_tsc_offset; > > mark_dirty(svm->vmcb, VMCB_INTERCEPTS); > + return svm->vmcb->control.tsc_offset; > } > > static void avic_init_vmcb(struct vcpu_svm *svm) > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c > index 4555077d69ce..20d90ebd6cc8 100644 > --- a/arch/x86/kvm/vmx.c > +++ b/arch/x86/kvm/vmx.c > @@ -3452,11 +3452,9 @@ static u64 vmx_read_l1_tsc_offset(struct kvm_vcpu *vcpu) > return vcpu->arch.tsc_offset; > } > > -/* > - * writes 'offset' into guest's timestamp counter offset register > - */ > -static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > +static u64 vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) > { > + u64 active_offset = l1_offset; > if (is_guest_mode(vcpu)) { > /* > * We're here if L1 chose not to trap WRMSR to TSC. According > @@ -3464,17 +3462,16 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > * set for L2 remains unchanged, and still needs to be added > * to the newly set TSC to get L2's TSC. > */ > - struct vmcs12 *vmcs12; > - /* recalculate vmcs02.TSC_OFFSET: */ > - vmcs12 = get_vmcs12(vcpu); > - vmcs_write64(TSC_OFFSET, offset + > - (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETING) ? > - vmcs12->tsc_offset : 0)); > + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); > + if (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETING)) > + active_offset += vmcs12->tsc_offset; > } else { > trace_kvm_write_tsc_offset(vcpu->vcpu_id, > - vmcs_read64(TSC_OFFSET), offset); > - vmcs_write64(TSC_OFFSET, offset); > + vmcs_read64(TSC_OFFSET), l1_offset); > } > + > + vmcs_write64(TSC_OFFSET, active_offset); > + return active_offset; > } > > /* > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 8525dc75a79a..c4e80af1a54e 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -1766,10 +1766,9 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc) > } > EXPORT_SYMBOL_GPL(kvm_read_l1_tsc); > > -static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > +static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) > { > - kvm_x86_ops->write_tsc_offset(vcpu, offset); > - vcpu->arch.tsc_offset = offset; > + vcpu->arch.tsc_offset = kvm_x86_ops->write_tsc_offset(vcpu, l1_offset); > } > > static inline bool kvm_check_tsc_unstable(void) > @@ -1897,7 +1896,8 @@ EXPORT_SYMBOL_GPL(kvm_write_tsc); > static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, > s64 adjustment) > { > - kvm_vcpu_write_tsc_offset(vcpu, vcpu->arch.tsc_offset + adjustment); > + u64 l1_tsc_offset = kvm_x86_ops->read_l1_tsc_offset(vcpu); > + kvm_vcpu_write_tsc_offset(vcpu, l1_tsc_offset + adjustment); > } > > static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment) > I queued v1, and will send a replacement for patch 2 of this miniseries. Paoo