Skip to content

Commit f459a70

Browse files
Sean Christophersonbonzini
authored andcommitted
KVM: VMX: modify preemption timer bit only when arming timer
Provide a singular location where the VMX preemption timer bit is set/cleared so that future usages of the preemption timer can ensure the VMCS bit is up-to-date without having to modify unrelated code paths. For example, the preemption timer can be used to force an immediate VMExit. Cache the status of the timer to avoid redundant VMREAD and VMWRITE, e.g. if the timer stays armed across multiple VMEnters/VMExits. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 4c00812 commit f459a70

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

arch/x86/kvm/vmx.c

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ struct loaded_vmcs {
397397
int cpu;
398398
bool launched;
399399
bool nmi_known_unmasked;
400+
bool hv_timer_armed;
400401
/* Support for vnmi-less CPUs */
401402
int soft_vnmi_blocked;
402403
ktime_t entry_time;
@@ -10595,24 +10596,38 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
1059510596
msrs[i].host, false);
1059610597
}
1059710598

10598-
static void vmx_arm_hv_timer(struct kvm_vcpu *vcpu)
10599+
static void vmx_arm_hv_timer(struct vcpu_vmx *vmx, u32 val)
10600+
{
10601+
vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, val);
10602+
if (!vmx->loaded_vmcs->hv_timer_armed)
10603+
vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
10604+
PIN_BASED_VMX_PREEMPTION_TIMER);
10605+
vmx->loaded_vmcs->hv_timer_armed = true;
10606+
}
10607+
10608+
static void vmx_update_hv_timer(struct kvm_vcpu *vcpu)
1059910609
{
1060010610
struct vcpu_vmx *vmx = to_vmx(vcpu);
1060110611
u64 tscl;
1060210612
u32 delta_tsc;
1060310613

10604-
if (vmx->hv_deadline_tsc == -1)
10605-
return;
10614+
if (vmx->hv_deadline_tsc != -1) {
10615+
tscl = rdtsc();
10616+
if (vmx->hv_deadline_tsc > tscl)
10617+
/* set_hv_timer ensures the delta fits in 32-bits */
10618+
delta_tsc = (u32)((vmx->hv_deadline_tsc - tscl) >>
10619+
cpu_preemption_timer_multi);
10620+
else
10621+
delta_tsc = 0;
1060610622

10607-
tscl = rdtsc();
10608-
if (vmx->hv_deadline_tsc > tscl)
10609-
/* sure to be 32 bit only because checked on set_hv_timer */
10610-
delta_tsc = (u32)((vmx->hv_deadline_tsc - tscl) >>
10611-
cpu_preemption_timer_multi);
10612-
else
10613-
delta_tsc = 0;
10623+
vmx_arm_hv_timer(vmx, delta_tsc);
10624+
return;
10625+
}
1061410626

10615-
vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc);
10627+
if (vmx->loaded_vmcs->hv_timer_armed)
10628+
vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
10629+
PIN_BASED_VMX_PREEMPTION_TIMER);
10630+
vmx->loaded_vmcs->hv_timer_armed = false;
1061610631
}
1061710632

1061810633
static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
@@ -10672,7 +10687,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
1067210687

1067310688
atomic_switch_perf_msrs(vmx);
1067410689

10675-
vmx_arm_hv_timer(vcpu);
10690+
vmx_update_hv_timer(vcpu);
1067610691

1067710692
/*
1067810693
* If this vCPU has touched SPEC_CTRL, restore the guest's value if
@@ -12078,11 +12093,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
1207812093

1207912094
exec_control = vmcs12->pin_based_vm_exec_control;
1208012095

12081-
/* Preemption timer setting is only taken from vmcs01. */
12082-
exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
12096+
/* Preemption timer setting is computed directly in vmx_vcpu_run. */
1208312097
exec_control |= vmcs_config.pin_based_exec_ctrl;
12084-
if (vmx->hv_deadline_tsc == -1)
12085-
exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
12098+
exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER;
12099+
vmx->loaded_vmcs->hv_timer_armed = false;
1208612100

1208712101
/* Posted interrupts setting is only taken from vmcs12. */
1208812102
if (nested_cpu_has_posted_intr(vmcs12)) {
@@ -13255,12 +13269,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
1325513269
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
1325613270
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
1325713271
vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
13258-
if (vmx->hv_deadline_tsc == -1)
13259-
vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
13260-
PIN_BASED_VMX_PREEMPTION_TIMER);
13261-
else
13262-
vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
13263-
PIN_BASED_VMX_PREEMPTION_TIMER);
13272+
1326413273
if (kvm_has_tsc_control)
1326513274
decache_tsc_multiplier(vmx);
1326613275

@@ -13464,18 +13473,12 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc)
1346413473
return -ERANGE;
1346513474

1346613475
vmx->hv_deadline_tsc = tscl + delta_tsc;
13467-
vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL,
13468-
PIN_BASED_VMX_PREEMPTION_TIMER);
13469-
1347013476
return delta_tsc == 0;
1347113477
}
1347213478

1347313479
static void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu)
1347413480
{
13475-
struct vcpu_vmx *vmx = to_vmx(vcpu);
13476-
vmx->hv_deadline_tsc = -1;
13477-
vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
13478-
PIN_BASED_VMX_PREEMPTION_TIMER);
13481+
to_vmx(vcpu)->hv_deadline_tsc = -1;
1347913482
}
1348013483
#endif
1348113484

0 commit comments

Comments
 (0)