diff mbox series

[v3,8/8] x86/HVM: don't needlessly intercept APERF/MPERF/TSC MSR reads

Message ID 88c2b2a3-e4fc-144a-1ba8-4983dd99a957@suse.com (mailing list archive)
State New, archived
Headers show
Series x86emul: further work | expand

Commit Message

Jan Beulich Sept. 3, 2019, 9:42 a.m. UTC
If the hardware can handle accesses, we should allow it to do so. This
way we can expose EFRO to HVM guests, and "all" that's left for exposing
APERF/MPERF is to figure out how to handle writes to these MSRs. (Note
that the leaf 6 guest CPUID checks will evaluate to false for now, as
recalculate_misc() zaps the entire leaf for now.)

For TSC I see little point in making the intercepts dynamic, hence they
get established right when a VMCB/VMCS gets created.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v3: New.

Comments

Boris Ostrovsky Sept. 4, 2019, 11:16 p.m. UTC | #1
On 9/3/19 5:42 AM, Jan Beulich wrote:
>
> For TSC I see little point in making the intercepts dynamic, hence they
> get established right when a VMCB/VMCS gets created.

Why is this not treated in the same manner as rdtsc intercepts?

-boris
Jan Beulich Sept. 5, 2019, 6:31 a.m. UTC | #2
On 05.09.2019 01:16, Boris Ostrovsky wrote:
> On 9/3/19 5:42 AM, Jan Beulich wrote:
>>
>> For TSC I see little point in making the intercepts dynamic, hence they
>> get established right when a VMCB/VMCS gets created.
> 
> Why is this not treated in the same manner as rdtsc intercepts?

Oh, indeed - I'll change this.

Jan
diff mbox series

Patch

--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -53,6 +53,7 @@  static int update_domain_cpuid_info(stru
     const struct cpuid_leaf leaf = { ctl->eax, ctl->ebx, ctl->ecx, ctl->edx };
     int old_vendor = p->x86_vendor;
     unsigned int old_7d0 = p->feat.raw[0].d, old_e8b = p->extd.raw[8].b;
+    unsigned int old_6c = p->basic.raw[6].c, old_e7d = p->extd.raw[7].d;
     bool call_policy_changed = false; /* Avoid for_each_vcpu() unnecessarily */
 
     /*
@@ -209,6 +210,14 @@  static int update_domain_cpuid_info(stru
 
             d->arch.pv.cpuidmasks->_6c = mask;
         }
+
+        /*
+         * If the APERF/MPERF policy has changed, we need to recalculate the
+         * MSR interception bitmaps.
+         */
+        call_policy_changed = (is_hvm_domain(d) &&
+                               ((old_6c ^ p->basic.raw[6].c) &
+                                CPUID6_ECX_APERFMPERF_CAPABILITY));
         break;
 
     case 7:
@@ -314,6 +323,16 @@  static int update_domain_cpuid_info(stru
         }
         break;
 
+    case 0x80000007:
+        /*
+         * If the EFRO policy has changed, we need to recalculate the MSR
+         * interception bitmaps.
+         */
+        call_policy_changed = (is_hvm_domain(d) &&
+                               ((old_e7d ^ p->extd.raw[7].d) &
+                                cpufeat_mask(X86_FEATURE_EFRO)));
+        break;
+
     case 0x80000008:
         /*
          * If the IBPB policy has changed, we need to recalculate the MSR
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -613,6 +613,7 @@  static void svm_cpuid_policy_changed(str
     struct vmcb_struct *vmcb = svm->vmcb;
     const struct cpuid_policy *cp = v->domain->arch.cpuid;
     u32 bitmap = vmcb_get_exception_intercepts(vmcb);
+    unsigned int mode;
 
     if ( opt_hvm_fep ||
          (v->domain->arch.cpuid->x86_vendor != boot_cpu_data.x86_vendor) )
@@ -625,6 +626,17 @@  static void svm_cpuid_policy_changed(str
     /* Give access to MSR_PRED_CMD if the guest has been told about it. */
     svm_intercept_msr(v, MSR_PRED_CMD,
                       cp->extd.ibpb ? MSR_INTERCEPT_NONE : MSR_INTERCEPT_RW);
+
+    /* Allow direct reads from APERF/MPERF if permitted by the policy. */
+    mode = cp->basic.raw[6].c & CPUID6_ECX_APERFMPERF_CAPABILITY
+           ? MSR_INTERCEPT_WRITE : MSR_INTERCEPT_RW;
+    svm_intercept_msr(v, MSR_IA32_APERF, mode);
+    svm_intercept_msr(v, MSR_IA32_MPERF, mode);
+
+    /* Allow direct access to their r/o counterparts if permitted. */
+    mode = cp->extd.efro ? MSR_INTERCEPT_NONE : MSR_INTERCEPT_RW;
+    svm_intercept_msr(v, MSR_APERF_RD_ONLY, mode);
+    svm_intercept_msr(v, MSR_MPERF_RD_ONLY, mode);
 }
 
 void svm_sync_vmcb(struct vcpu *v, enum vmcb_sync_state new_state)
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -92,6 +92,7 @@  static int construct_vmcb(struct vcpu *v
         return -ENOMEM;
     memset(svm->msrpm, 0xff, MSRPM_SIZE);
 
+    svm_intercept_msr(v, MSR_IA32_TSC, MSR_INTERCEPT_WRITE);
     svm_disable_intercept_for_msr(v, MSR_FS_BASE);
     svm_disable_intercept_for_msr(v, MSR_GS_BASE);
     svm_disable_intercept_for_msr(v, MSR_SHADOW_GS_BASE);
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1081,6 +1081,7 @@  static int construct_vmcs(struct vcpu *v
         v->arch.hvm.vmx.msr_bitmap = msr_bitmap;
         __vmwrite(MSR_BITMAP, virt_to_maddr(msr_bitmap));
 
+        vmx_clear_msr_intercept(v, MSR_IA32_TSC, VMX_MSR_R);
         vmx_clear_msr_intercept(v, MSR_FS_BASE, VMX_MSR_RW);
         vmx_clear_msr_intercept(v, MSR_GS_BASE, VMX_MSR_RW);
         vmx_clear_msr_intercept(v, MSR_SHADOW_GS_BASE, VMX_MSR_RW);
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -578,6 +578,18 @@  static void vmx_cpuid_policy_changed(str
         vmx_clear_msr_intercept(v, MSR_FLUSH_CMD, VMX_MSR_RW);
     else
         vmx_set_msr_intercept(v, MSR_FLUSH_CMD, VMX_MSR_RW);
+
+    /* Allow direct reads from APERF/MPERF if permitted by the policy. */
+    if ( cp->basic.raw[6].c & CPUID6_ECX_APERFMPERF_CAPABILITY )
+    {
+        vmx_clear_msr_intercept(v, MSR_IA32_APERF, VMX_MSR_R);
+        vmx_clear_msr_intercept(v, MSR_IA32_MPERF, VMX_MSR_R);
+    }
+    else
+    {
+        vmx_set_msr_intercept(v, MSR_IA32_APERF, VMX_MSR_R);
+        vmx_set_msr_intercept(v, MSR_IA32_MPERF, VMX_MSR_R);
+    }
 }
 
 int vmx_guest_x86_mode(struct vcpu *v)
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -242,7 +242,7 @@  XEN_CPUFEATURE(MOVDIR64B,     6*32+28) /
 
 /* AMD-defined CPU features, CPUID level 0x80000007.edx, word 7 */
 XEN_CPUFEATURE(ITSC,          7*32+ 8) /*   Invariant TSC */
-XEN_CPUFEATURE(EFRO,          7*32+10) /*   APERF/MPERF Read Only interface */
+XEN_CPUFEATURE(EFRO,          7*32+10) /*S  APERF/MPERF Read Only interface */
 
 /* AMD-defined CPU features, CPUID level 0x80000008.ebx, word 8 */
 XEN_CPUFEATURE(CLZERO,        8*32+ 0) /*A  CLZERO instruction */