summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kvm/vmx/nested.c71
-rw-r--r--arch/x86/kvm/vmx/vmx.c2
-rw-r--r--arch/x86/kvm/vmx/vmx.h2
3 files changed, 24 insertions, 51 deletions
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 486789dac515..614b789ecf16 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -1075,16 +1075,12 @@ static bool nested_vmx_get_vmexit_msr_value(struct kvm_vcpu *vcpu,
* does not include the time taken for emulation of the L2->L1
* VM-exit in L0, use the more accurate value.
*/
- if (msr_index == MSR_IA32_TSC) {
- int i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore,
- MSR_IA32_TSC);
+ if (msr_index == MSR_IA32_TSC && vmx->nested.tsc_autostore_slot >= 0) {
+ int slot = vmx->nested.tsc_autostore_slot;
+ u64 host_tsc = vmx->msr_autostore.val[slot].value;
- if (i >= 0) {
- u64 val = vmx->msr_autostore.val[i].value;
-
- *data = kvm_read_l1_tsc(vcpu, val);
- return true;
- }
+ *data = kvm_read_l1_tsc(vcpu, host_tsc);
+ return true;
}
if (kvm_emulate_msr_read(vcpu, msr_index, data)) {
@@ -1163,42 +1159,6 @@ static bool nested_msr_store_list_has_msr(struct kvm_vcpu *vcpu, u32 msr_index)
return false;
}
-static void prepare_vmx_msr_autostore_list(struct kvm_vcpu *vcpu,
- u32 msr_index)
-{
- struct vcpu_vmx *vmx = to_vmx(vcpu);
- struct vmx_msrs *autostore = &vmx->msr_autostore;
- bool in_vmcs12_store_list;
- int msr_autostore_slot;
- bool in_autostore_list;
- int last;
-
- msr_autostore_slot = vmx_find_loadstore_msr_slot(autostore, msr_index);
- in_autostore_list = msr_autostore_slot >= 0;
- in_vmcs12_store_list = nested_msr_store_list_has_msr(vcpu, msr_index);
-
- if (in_vmcs12_store_list && !in_autostore_list) {
- if (autostore->nr == MAX_NR_LOADSTORE_MSRS) {
- /*
- * Emulated VMEntry does not fail here. Instead a less
- * accurate value will be returned by
- * nested_vmx_get_vmexit_msr_value() by reading KVM's
- * internal MSR state instead of reading the value from
- * the vmcs02 VMExit MSR-store area.
- */
- pr_warn_ratelimited(
- "Not enough msr entries in msr_autostore. Can't add msr %x\n",
- msr_index);
- return;
- }
- last = autostore->nr++;
- autostore->val[last].index = msr_index;
- } else if (!in_vmcs12_store_list && in_autostore_list) {
- last = --autostore->nr;
- autostore->val[msr_autostore_slot] = autostore->val[last];
- }
-}
-
/*
* Load guest's/host's cr3 at nested entry/exit. @nested_ept is true if we are
* emulating VM-Entry into a guest with EPT enabled. On failure, the expected
@@ -2699,12 +2659,25 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
}
/*
- * Make sure the msr_autostore list is up to date before we set the
- * count in the vmcs02.
+ * If vmcs12 is configured to save TSC on exit via the auto-store list,
+ * append the MSR to vmcs02's auto-store list so that KVM effectively
+ * reads TSC at the time of VM-Exit from L2. The saved value will be
+ * propagated to vmcs12's list on nested VM-Exit.
+ *
+ * Don't increment the number of MSRs in the vCPU structure, as saving
+ * TSC is specific to this particular incarnation of vmcb02, i.e. must
+ * not bleed into vmcs01.
*/
- prepare_vmx_msr_autostore_list(&vmx->vcpu, MSR_IA32_TSC);
+ if (nested_msr_store_list_has_msr(&vmx->vcpu, MSR_IA32_TSC) &&
+ !WARN_ON_ONCE(vmx->msr_autostore.nr >= ARRAY_SIZE(vmx->msr_autostore.val))) {
+ vmx->nested.tsc_autostore_slot = vmx->msr_autostore.nr;
+ vmx->msr_autostore.val[vmx->msr_autostore.nr].index = MSR_IA32_TSC;
- vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
+ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr + 1);
+ } else {
+ vmx->nested.tsc_autostore_slot = -1;
+ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, vmx->msr_autostore.nr);
+ }
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr);
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 23c92c41fd83..52bcb817cc15 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -1029,7 +1029,7 @@ static __always_inline void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx
vm_exit_controls_clearbit(vmx, exit);
}
-int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
+static int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr)
{
unsigned int i;
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index 4ce653d729ca..3175fedb5a4d 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -191,6 +191,7 @@ struct nested_vmx {
u16 vpid02;
u16 last_vpid;
+ int tsc_autostore_slot;
struct nested_vmx_msrs msrs;
/* SMM related state */
@@ -383,7 +384,6 @@ void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
unsigned int flags);
-int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr);
void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type, bool set);