History

KVM: x86: Provide a capability to disable APERF/MPERF read intercepts

Allow a guest to read the physical IA32_APERF and IA32_MPERF MSRs without interception. The IA32_APERF and IA32_MPERF MSRs are not virtualized. Writes are not handled at all. The MSR values are not zeroed on vCPU creation, saved on suspend, or restored on resume. No accommodation is made for processor migration or for sharing a logical processor with other tasks. No adjustments are made for non-unit TSC multipliers. The MSRs do not account for time the same way as the comparable PMU events, whether the PMU is virtualized by the traditional emulation method or the new mediated pass-through approach. Nonetheless, in a properly constrained environment, this capability can be combined with a guest CPUID table that advertises support for CPUID.6:ECX.APERFMPERF[bit 0] to induce a Linux guest to report the effective physical CPU frequency in /proc/cpuinfo. Moreover, there is no performance cost for this capability.

Jim Mattson committed 1 year ago

Commit a7cec201 parent 6fbef869 files · +53 −2Browse files

Unified · Split

9 files
  1. Documentation/virt/kvm/api.rst +23 −0
  2. arch/x86/kvm/svm/nested.c +3 −1
  3. arch/x86/kvm/svm/svm.c +5 −0
  4. arch/x86/kvm/vmx/nested.c +6 −0
  5. arch/x86/kvm/vmx/vmx.c +4 −0
  6. arch/x86/kvm/x86.c +5 −1
  7. arch/x86/kvm/x86.h +5 −0
  8. include/uapi/linux/kvm.h +1 −0
  9. tools/include/uapi/linux/kvm.h +1 −0
Documentation/virt/kvm/api.rst+23−0
@@ -7844,6 +7844,7 @@ Valid bits in args[0] are:: · 7843 unmodified lines
7844 #define KVM_X86_DISABLE_EXITS_HLT (1 << 1)7844 #define KVM_X86_DISABLE_EXITS_HLT (1 << 1)
7845 #define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)7845 #define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)
7846 #define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)7846 #define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)
7847 #define KVM_X86_DISABLE_EXITS_APERFMPERF (1 << 4)
7847 7848
7848Enabling this capability on a VM provides userspace with a way to no7849Enabling this capability on a VM provides userspace with a way to no
7849longer intercept some instructions for improved latency in some7850longer intercept some instructions for improved latency in some
@@ -7854,6 +7855,28 @@ all such vmexits. · 4 unmodified lines
7854 7855
7855Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits.7856Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits.
7856 7857
7858Virtualizing the ``IA32_APERF`` and ``IA32_MPERF`` MSRs requires more
7859than just disabling APERF/MPERF exits. While both Intel and AMD
7860document strict usage conditions for these MSRs--emphasizing that only
7861the ratio of their deltas over a time interval (T0 to T1) is
7862architecturally defined--simply passing through the MSRs can still
7863produce an incorrect ratio.
7864
7865This erroneous ratio can occur if, between T0 and T1:
7866
78671. The vCPU thread migrates between logical processors.
78682. Live migration or suspend/resume operations take place.
78693. Another task shares the vCPU's logical processor.
78704. C-states lower than C0 are emulated (e.g., via HLT interception).
78715. The guest TSC frequency doesn't match the host TSC frequency.
7872
7873Due to these complexities, KVM does not automatically associate this
7874passthrough capability with the guest CPUID bit,
7875``CPUID.6:ECX.APERFMPERF[bit 0]``. Userspace VMMs that deem this
7876mechanism adequate for virtualizing the ``IA32_APERF`` and
7877``IA32_MPERF`` MSRs must set the guest CPUID bit explicitly.
7878
7879
78577.14 KVM_CAP_S390_HPAGE_1M78807.14 KVM_CAP_S390_HPAGE_1M
7858--------------------------7881--------------------------
7859 7882
arch/x86/kvm/svm/nested.c+3−1
@@ -194,7 +194,7 @@ void recalc_intercepts(struct vcpu_svm *svm) · 193 unmodified lines
194 * Hardcode the capacity of the array based on the maximum number of _offsets_.194 * Hardcode the capacity of the array based on the maximum number of _offsets_.
195 * MSRs are batched together, so there are fewer offsets than MSRs.195 * MSRs are batched together, so there are fewer offsets than MSRs.
196 */196 */
197static int nested_svm_msrpm_merge_offsets[6] __ro_after_init;197static int nested_svm_msrpm_merge_offsets[7] __ro_after_init;
198static int nested_svm_nr_msrpm_merge_offsets __ro_after_init;198static int nested_svm_nr_msrpm_merge_offsets __ro_after_init;
199typedef unsigned long nsvm_msrpm_merge_t;199typedef unsigned long nsvm_msrpm_merge_t;
200 200
@@ -216,6 +216,8 @@ int __init nested_svm_init_msrpm_merge_offsets(void) · 15 unmodified lines
216 MSR_IA32_SPEC_CTRL,216 MSR_IA32_SPEC_CTRL,
217 MSR_IA32_PRED_CMD,217 MSR_IA32_PRED_CMD,
218 MSR_IA32_FLUSH_CMD,218 MSR_IA32_FLUSH_CMD,
219 MSR_IA32_APERF,
220 MSR_IA32_MPERF,
219 MSR_IA32_LASTBRANCHFROMIP,221 MSR_IA32_LASTBRANCHFROMIP,
220 MSR_IA32_LASTBRANCHTOIP,222 MSR_IA32_LASTBRANCHTOIP,
221 MSR_IA32_LASTINTFROMIP,223 MSR_IA32_LASTINTFROMIP,
arch/x86/kvm/svm/svm.c+5−0
@@ -838,6 +838,11 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu) · 837 unmodified lines
838 svm_set_intercept_for_msr(vcpu, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW,838 svm_set_intercept_for_msr(vcpu, MSR_IA32_SYSENTER_ESP, MSR_TYPE_RW,
839 guest_cpuid_is_intel_compatible(vcpu));839 guest_cpuid_is_intel_compatible(vcpu));
840 840
841 if (kvm_aperfmperf_in_guest(vcpu->kvm)) {
842 svm_disable_intercept_for_msr(vcpu, MSR_IA32_APERF, MSR_TYPE_R);
843 svm_disable_intercept_for_msr(vcpu, MSR_IA32_MPERF, MSR_TYPE_R);
844 }
845
841 if (sev_es_guest(vcpu->kvm))846 if (sev_es_guest(vcpu->kvm))
842 sev_es_recalc_msr_intercepts(vcpu);847 sev_es_recalc_msr_intercepts(vcpu);
843 848
arch/x86/kvm/vmx/nested.c+6−0
@@ -715,6 +715,12 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, · 714 unmodified lines
715 nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,715 nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
716 MSR_IA32_FLUSH_CMD, MSR_TYPE_W);716 MSR_IA32_FLUSH_CMD, MSR_TYPE_W);
717 717
718 nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
719 MSR_IA32_APERF, MSR_TYPE_R);
720
721 nested_vmx_set_intercept_for_msr(vmx, msr_bitmap_l1, msr_bitmap_l0,
722 MSR_IA32_MPERF, MSR_TYPE_R);
723
718 kvm_vcpu_unmap(vcpu, &map);724 kvm_vcpu_unmap(vcpu, &map);
719 725
720 vmx->nested.force_msr_bitmap_recalc = false;726 vmx->nested.force_msr_bitmap_recalc = false;
arch/x86/kvm/vmx/vmx.c+4−0
@@ -4084,6 +4084,10 @@ void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu) · 4083 unmodified lines
4084 vmx_disable_intercept_for_msr(vcpu, MSR_CORE_C6_RESIDENCY, MSR_TYPE_R);4084 vmx_disable_intercept_for_msr(vcpu, MSR_CORE_C6_RESIDENCY, MSR_TYPE_R);
4085 vmx_disable_intercept_for_msr(vcpu, MSR_CORE_C7_RESIDENCY, MSR_TYPE_R);4085 vmx_disable_intercept_for_msr(vcpu, MSR_CORE_C7_RESIDENCY, MSR_TYPE_R);
4086 }4086 }
4087 if (kvm_aperfmperf_in_guest(vcpu->kvm)) {
4088 vmx_disable_intercept_for_msr(vcpu, MSR_IA32_APERF, MSR_TYPE_R);
4089 vmx_disable_intercept_for_msr(vcpu, MSR_IA32_MPERF, MSR_TYPE_R);
4090 }
4087 4091
4088 /* PT MSRs can be passed through iff PT is exposed to the guest. */4092 /* PT MSRs can be passed through iff PT is exposed to the guest. */
4089 if (vmx_pt_mode_is_host_guest())4093 if (vmx_pt_mode_is_host_guest())
arch/x86/kvm/x86.c+5−1
@@ -4577,6 +4577,9 @@ static u64 kvm_get_allowed_disable_exits(void) · 4576 unmodified lines
4577{4577{
4578 u64 r = KVM_X86_DISABLE_EXITS_PAUSE;4578 u64 r = KVM_X86_DISABLE_EXITS_PAUSE;
4579 4579
4580 if (boot_cpu_has(X86_FEATURE_APERFMPERF))
4581 r |= KVM_X86_DISABLE_EXITS_APERFMPERF;
4582
4580 if (!mitigate_smt_rsb) {4583 if (!mitigate_smt_rsb) {
4581 r |= KVM_X86_DISABLE_EXITS_HLT |4584 r |= KVM_X86_DISABLE_EXITS_HLT |
4582 KVM_X86_DISABLE_EXITS_CSTATE;4585 KVM_X86_DISABLE_EXITS_CSTATE;
@@ -6613,7 +6616,8 @@ split_irqchip_unlock: · 2030 unmodified lines
6613 6616
6614 if (!mitigate_smt_rsb && boot_cpu_has_bug(X86_BUG_SMT_RSB) &&6617 if (!mitigate_smt_rsb && boot_cpu_has_bug(X86_BUG_SMT_RSB) &&
6615 cpu_smt_possible() &&6618 cpu_smt_possible() &&
6616 (cap->args[0] & ~KVM_X86_DISABLE_EXITS_PAUSE))6619 (cap->args[0] & ~(KVM_X86_DISABLE_EXITS_PAUSE |
6620 KVM_X86_DISABLE_EXITS_APERFMPERF)))
6617 pr_warn_once(SMT_RSB_MSG);6621 pr_warn_once(SMT_RSB_MSG);
6618 6622
6619 kvm_disable_exits(kvm, cap->args[0]);6623 kvm_disable_exits(kvm, cap->args[0]);
arch/x86/kvm/x86.h+5−0
@@ -524,6 +524,11 @@ static inline bool kvm_cstate_in_guest(struct kvm *kvm) · 523 unmodified lines
524 return kvm->arch.disabled_exits & KVM_X86_DISABLE_EXITS_CSTATE;524 return kvm->arch.disabled_exits & KVM_X86_DISABLE_EXITS_CSTATE;
525}525}
526 526
527static inline bool kvm_aperfmperf_in_guest(struct kvm *kvm)
528{
529 return kvm->arch.disabled_exits & KVM_X86_DISABLE_EXITS_APERFMPERF;
530}
531
527static inline bool kvm_notify_vmexit_enabled(struct kvm *kvm)532static inline bool kvm_notify_vmexit_enabled(struct kvm *kvm)
528{533{
529 return kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_ENABLED;534 return kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_ENABLED;
include/uapi/linux/kvm.h+1−0
@@ -644,6 +644,7 @@ struct kvm_ioeventfd { · 643 unmodified lines
644#define KVM_X86_DISABLE_EXITS_HLT (1 << 1)644#define KVM_X86_DISABLE_EXITS_HLT (1 << 1)
645#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)645#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)
646#define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)646#define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)
647#define KVM_X86_DISABLE_EXITS_APERFMPERF (1 << 4)
647 648
648/* for KVM_ENABLE_CAP */649/* for KVM_ENABLE_CAP */
649struct kvm_enable_cap {650struct kvm_enable_cap {
tools/include/uapi/linux/kvm.h+1−0
@@ -617,6 +617,7 @@ struct kvm_ioeventfd { · 616 unmodified lines
617#define KVM_X86_DISABLE_EXITS_HLT (1 << 1)617#define KVM_X86_DISABLE_EXITS_HLT (1 << 1)
618#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)618#define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2)
619#define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)619#define KVM_X86_DISABLE_EXITS_CSTATE (1 << 3)
620#define KVM_X86_DISABLE_EXITS_APERFMPERF (1 << 4)
620 621
621/* for KVM_ENABLE_CAP */622/* for KVM_ENABLE_CAP */
622struct kvm_enable_cap {623struct kvm_enable_cap {