@@ -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
@@ -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)
@@ -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);
@@ -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);
@@ -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)
@@ -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 */
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.