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>
This commit is contained in:

committed by
Paolo Bonzini

parent
4e1acd7b31
commit
e79f245dde
@@ -2874,6 +2874,17 @@ static void setup_msrs(struct vcpu_vmx *vmx)
|
||||
vmx_update_msr_bitmap(&vmx->vcpu);
|
||||
}
|
||||
|
||||
static u64 vmx_read_l1_tsc_offset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
||||
|
||||
if (is_guest_mode(vcpu) &&
|
||||
(vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING))
|
||||
return vcpu->arch.tsc_offset - vmcs12->tsc_offset;
|
||||
|
||||
return vcpu->arch.tsc_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* reads and returns guest's timestamp counter "register"
|
||||
* guest_tsc = (host_tsc * tsc multiplier) >> 48 + tsc_offset
|
||||
@@ -11175,11 +11186,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
||||
vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat);
|
||||
}
|
||||
|
||||
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
|
||||
vmcs_write64(TSC_OFFSET,
|
||||
vcpu->arch.tsc_offset + vmcs12->tsc_offset);
|
||||
else
|
||||
vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
|
||||
vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
|
||||
|
||||
if (kvm_has_tsc_control)
|
||||
decache_tsc_multiplier(vmx);
|
||||
|
||||
@@ -11427,6 +11435,7 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
|
||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
||||
u32 msr_entry_idx;
|
||||
u32 exit_qual;
|
||||
int r;
|
||||
|
||||
enter_guest_mode(vcpu);
|
||||
|
||||
@@ -11436,26 +11445,21 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
|
||||
vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02);
|
||||
vmx_segment_cache_clear(vmx);
|
||||
|
||||
if (prepare_vmcs02(vcpu, vmcs12, from_vmentry, &exit_qual)) {
|
||||
leave_guest_mode(vcpu);
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
nested_vmx_entry_failure(vcpu, vmcs12,
|
||||
EXIT_REASON_INVALID_STATE, exit_qual);
|
||||
return 1;
|
||||
}
|
||||
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
|
||||
vcpu->arch.tsc_offset += vmcs12->tsc_offset;
|
||||
|
||||
r = EXIT_REASON_INVALID_STATE;
|
||||
if (prepare_vmcs02(vcpu, vmcs12, from_vmentry, &exit_qual))
|
||||
goto fail;
|
||||
|
||||
nested_get_vmcs12_pages(vcpu, vmcs12);
|
||||
|
||||
r = EXIT_REASON_MSR_LOAD_FAIL;
|
||||
msr_entry_idx = nested_vmx_load_msr(vcpu,
|
||||
vmcs12->vm_entry_msr_load_addr,
|
||||
vmcs12->vm_entry_msr_load_count);
|
||||
if (msr_entry_idx) {
|
||||
leave_guest_mode(vcpu);
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
nested_vmx_entry_failure(vcpu, vmcs12,
|
||||
EXIT_REASON_MSR_LOAD_FAIL, msr_entry_idx);
|
||||
return 1;
|
||||
}
|
||||
if (msr_entry_idx)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* Note no nested_vmx_succeed or nested_vmx_fail here. At this point
|
||||
@@ -11464,6 +11468,14 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
|
||||
* the success flag) when L2 exits (see nested_vmx_vmexit()).
|
||||
*/
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
|
||||
vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
|
||||
leave_guest_mode(vcpu);
|
||||
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
|
||||
nested_vmx_entry_failure(vcpu, vmcs12, r, exit_qual);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -12035,6 +12047,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
|
||||
|
||||
leave_guest_mode(vcpu);
|
||||
|
||||
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
|
||||
vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
|
||||
|
||||
if (likely(!vmx->fail)) {
|
||||
if (exit_reason == -1)
|
||||
sync_vmcs12(vcpu, vmcs12);
|
||||
@@ -12725,6 +12740,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
|
||||
|
||||
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
|
||||
|
||||
.read_l1_tsc_offset = vmx_read_l1_tsc_offset,
|
||||
.write_tsc_offset = vmx_write_tsc_offset,
|
||||
|
||||
.set_tdp_cr3 = vmx_set_cr3,
|
||||
|
Reference in New Issue
Block a user