This is a followup to c/s
96f235c26 which fulfils the remaining TODO item.
First of all, the pre-existing SVM code has a bug. The value in
msrs->dr_mask[] may be stale, as we allow direct access to these MSRs.
Resolve this in guest_rdmsr() by reading directly from hardware in the
affected case.
With the reading/writing logic moved to the common guest_{rd,wr}msr()
infrastructure, the migration logic can be simplified. The PV migration logic
drops all of its special casing, and SVM's entire {init,save,load}_msr()
infrastructure becomes unnecessary.
The resulting diffstat shows quite how expensive the PV special cases where in
arch_do_domctl().
add/remove: 0/3 grow/shrink: 4/6 up/down: 465/-1494 (-1029)
Function old new delta
guest_rdmsr 252 484 +232
guest_wrmsr 653 822 +169
msrs_to_send 8 48 +40
hvm_load_cpu_msrs 489 513 +24
svm_init_msr 21 - -21
hvm_save_cpu_msrs 365 343 -22
read_msr 1089 1001 -88
write_msr 1829 1689 -140
svm_msr_read_intercept 1124 970 -154
svm_load_msr 195 - -195
svm_save_msr 196 - -196
svm_msr_write_intercept 1461 1265 -196
arch_do_domctl 9581 9099 -482
Total: Before=
3314610, After=
3313581, chg -0.03%
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
static const uint32_t msrs_to_send[] = {
MSR_SPEC_CTRL,
MSR_INTEL_MISC_FEATURES_ENABLES,
+ MSR_AMD64_DR0_ADDRESS_MASK,
+ MSR_AMD64_DR1_ADDRESS_MASK,
+ MSR_AMD64_DR2_ADDRESS_MASK,
+ MSR_AMD64_DR3_ADDRESS_MASK,
};
uint32_t nr_msrs = ARRAY_SIZE(msrs_to_send);
++i;
}
- if ( boot_cpu_has(X86_FEATURE_DBEXT) )
- {
- if ( v->arch.msrs->dr_mask[0] )
- {
- if ( i < vmsrs->msr_count && !ret )
- {
- msr.index = MSR_AMD64_DR0_ADDRESS_MASK;
- msr.value = v->arch.msrs->dr_mask[0];
- if ( copy_to_guest_offset(vmsrs->msrs, i, &msr, 1) )
- ret = -EFAULT;
- }
- ++i;
- }
-
- for ( j = 0; j < 3; ++j )
- {
- if ( !v->arch.msrs->dr_mask[1 + j] )
- continue;
- if ( i < vmsrs->msr_count && !ret )
- {
- msr.index = MSR_AMD64_DR1_ADDRESS_MASK + j;
- msr.value = v->arch.msrs->dr_mask[1 + j];
- if ( copy_to_guest_offset(vmsrs->msrs, i, &msr, 1) )
- ret = -EFAULT;
- }
- ++i;
- }
- }
-
vcpu_unpause(v);
if ( i > vmsrs->msr_count && !ret )
{
case MSR_SPEC_CTRL:
case MSR_INTEL_MISC_FEATURES_ENABLES:
- if ( guest_wrmsr(v, msr.index, msr.value) != X86EMUL_OKAY )
- break;
- continue;
-
case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) ||
- (msr.value >> 32) )
- break;
- v->arch.msrs->dr_mask[0] = msr.value;
- continue;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ...
- MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) ||
- (msr.value >> 32) )
+ case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
+ if ( guest_wrmsr(v, msr.index, msr.value) != X86EMUL_OKAY )
break;
- msr.index -= MSR_AMD64_DR1_ADDRESS_MASK - 1;
- v->arch.msrs->dr_mask[msr.index] = msr.value;
continue;
}
break;
static const uint32_t msrs_to_send[] = {
MSR_SPEC_CTRL,
MSR_INTEL_MISC_FEATURES_ENABLES,
+ MSR_AMD64_DR0_ADDRESS_MASK,
+ MSR_AMD64_DR1_ADDRESS_MASK,
+ MSR_AMD64_DR2_ADDRESS_MASK,
+ MSR_AMD64_DR3_ADDRESS_MASK,
};
static unsigned int __read_mostly msr_count_max = ARRAY_SIZE(msrs_to_send);
case MSR_SPEC_CTRL:
case MSR_INTEL_MISC_FEATURES_ENABLES:
+ case MSR_AMD64_DR0_ADDRESS_MASK:
+ case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
rc = guest_wrmsr(v, ctxt->msr[i].index, ctxt->msr[i].val);
if ( rc != X86EMUL_OKAY )
return 0;
}
-static unsigned int __init svm_init_msr(void)
-{
- return boot_cpu_has(X86_FEATURE_DBEXT) ? 4 : 0;
-}
-
-static void svm_save_msr(struct vcpu *v, struct hvm_msr *ctxt)
-{
- if ( boot_cpu_has(X86_FEATURE_DBEXT) )
- {
- ctxt->msr[ctxt->count].val = v->arch.msrs->dr_mask[0];
- if ( ctxt->msr[ctxt->count].val )
- ctxt->msr[ctxt->count++].index = MSR_AMD64_DR0_ADDRESS_MASK;
-
- ctxt->msr[ctxt->count].val = v->arch.msrs->dr_mask[1];
- if ( ctxt->msr[ctxt->count].val )
- ctxt->msr[ctxt->count++].index = MSR_AMD64_DR1_ADDRESS_MASK;
-
- ctxt->msr[ctxt->count].val = v->arch.msrs->dr_mask[2];
- if ( ctxt->msr[ctxt->count].val )
- ctxt->msr[ctxt->count++].index = MSR_AMD64_DR2_ADDRESS_MASK;
-
- ctxt->msr[ctxt->count].val = v->arch.msrs->dr_mask[3];
- if ( ctxt->msr[ctxt->count].val )
- ctxt->msr[ctxt->count++].index = MSR_AMD64_DR3_ADDRESS_MASK;
- }
-}
-
-static int svm_load_msr(struct vcpu *v, struct hvm_msr *ctxt)
-{
- unsigned int i, idx;
- int err = 0;
-
- for ( i = 0; i < ctxt->count; ++i )
- {
- switch ( idx = ctxt->msr[i].index )
- {
- case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) )
- err = -ENXIO;
- else if ( ctxt->msr[i].val >> 32 )
- err = -EDOM;
- else
- v->arch.msrs->dr_mask[0] = ctxt->msr[i].val;
- break;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) )
- err = -ENXIO;
- else if ( ctxt->msr[i].val >> 32 )
- err = -EDOM;
- else
- v->arch.msrs->dr_mask[idx - MSR_AMD64_DR1_ADDRESS_MASK + 1] =
- ctxt->msr[i].val;
- break;
-
- default:
- continue;
- }
- if ( err )
- break;
- ctxt->msr[i]._rsvd = 1;
- }
-
- return err;
-}
-
static void svm_fpu_enter(struct vcpu *v)
{
struct vmcb_struct *n1vmcb = vcpu_nestedhvm(v).nv_n1vmcx;
goto gpf;
break;
- case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !v->domain->arch.cpuid->extd.dbext )
- goto gpf;
- *msr_content = v->arch.msrs->dr_mask[0];
- break;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !v->domain->arch.cpuid->extd.dbext )
- goto gpf;
- *msr_content =
- v->arch.msrs->dr_mask[msr - MSR_AMD64_DR1_ADDRESS_MASK + 1];
- break;
-
case MSR_AMD_OSVW_ID_LENGTH:
case MSR_AMD_OSVW_STATUS:
if ( !d->arch.cpuid->extd.osvw )
*/
break;
- case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !v->domain->arch.cpuid->extd.dbext || (msr_content >> 32) )
- goto gpf;
- v->arch.msrs->dr_mask[0] = msr_content;
- break;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !v->domain->arch.cpuid->extd.dbext || (msr_content >> 32) )
- goto gpf;
- v->arch.msrs->dr_mask[msr - MSR_AMD64_DR1_ADDRESS_MASK + 1] =
- msr_content;
- break;
-
case MSR_AMD_OSVW_ID_LENGTH:
case MSR_AMD_OSVW_STATUS:
if ( !d->arch.cpuid->extd.osvw )
.vcpu_destroy = svm_vcpu_destroy,
.save_cpu_ctxt = svm_save_vmcb_ctxt,
.load_cpu_ctxt = svm_load_vmcb_ctxt,
- .init_msr = svm_init_msr,
- .save_msr = svm_save_msr,
- .load_msr = svm_load_msr,
.get_interrupt_shadow = svm_get_interrupt_shadow,
.set_interrupt_shadow = svm_set_interrupt_shadow,
.guest_x86_mode = svm_guest_x86_mode,
#include <xen/init.h>
#include <xen/lib.h>
+#include <xen/nospec.h>
#include <xen/sched.h>
+
+#include <asm/debugreg.h>
#include <asm/msr.h>
DEFINE_PER_CPU(uint32_t, tsc_aux);
ret = guest_rdmsr_xen(v, msr, val);
break;
+ case MSR_AMD64_DR0_ADDRESS_MASK:
+ case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
+ if ( !cp->extd.dbext )
+ goto gp_fault;
+
+ /*
+ * In HVM context when we've allowed the guest direct access to debug
+ * registers, the value in msrs->dr_mask[] may be stale. Re-read it
+ * out of hardware.
+ */
+#ifdef CONFIG_HVM
+ if ( v == current && is_hvm_domain(d) && v->arch.hvm.flag_dr_dirty )
+ rdmsrl(msr, *val);
+ else
+#endif
+ *val = msrs->dr_mask[
+ array_index_nospec((msr == MSR_AMD64_DR0_ADDRESS_MASK)
+ ? 0 : (msr - MSR_AMD64_DR1_ADDRESS_MASK + 1),
+ ARRAY_SIZE(msrs->dr_mask))];
+ break;
+
default:
return X86EMUL_UNHANDLEABLE;
}
ret = guest_wrmsr_xen(v, msr, val);
break;
+ case MSR_AMD64_DR0_ADDRESS_MASK:
+ case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
+ if ( !cp->extd.dbext || val != (uint32_t)val )
+ goto gp_fault;
+
+ msrs->dr_mask[
+ array_index_nospec((msr == MSR_AMD64_DR0_ADDRESS_MASK)
+ ? 0 : (msr - MSR_AMD64_DR1_ADDRESS_MASK + 1),
+ ARRAY_SIZE(msrs->dr_mask))] = val;
+
+ if ( v == curr && (curr->arch.dr7 & DR7_ACTIVE_MASK) )
+ wrmsrl(msr, val);
+ break;
+
default:
return X86EMUL_UNHANDLEABLE;
}
*val = guest_misc_enable(*val);
return X86EMUL_OKAY;
- case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) )
- break;
- *val = curr->arch.msrs->dr_mask[0];
- return X86EMUL_OKAY;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) )
- break;
- *val = curr->arch.msrs->dr_mask[reg - MSR_AMD64_DR1_ADDRESS_MASK + 1];
- return X86EMUL_OKAY;
-
case MSR_IA32_PERF_CAPABILITIES:
/* No extra capabilities are supported. */
*val = 0;
return X86EMUL_OKAY;
break;
- case MSR_AMD64_DR0_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) || (val >> 32) )
- break;
- curr->arch.msrs->dr_mask[0] = val;
- if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
- wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, val);
- return X86EMUL_OKAY;
-
- case MSR_AMD64_DR1_ADDRESS_MASK ... MSR_AMD64_DR3_ADDRESS_MASK:
- if ( !boot_cpu_has(X86_FEATURE_DBEXT) || (val >> 32) )
- break;
- curr->arch.msrs->dr_mask[reg - MSR_AMD64_DR1_ADDRESS_MASK + 1] = val;
- if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
- wrmsrl(reg, val);
- return X86EMUL_OKAY;
-
case MSR_P6_PERFCTR(0) ... MSR_P6_PERFCTR(7):
case MSR_P6_EVNTSEL(0) ... MSR_P6_EVNTSEL(3):
case MSR_CORE_PERF_FIXED_CTR0 ... MSR_CORE_PERF_FIXED_CTR2:
/*
* 0xc00110{27,19-1b} MSR_AMD64_DR{0-3}_ADDRESS_MASK
- * TODO: Not yet handled by guest_{rd,wr}msr() infrastructure.
+ *
+ * Loaded into hardware for guests which have active %dr7 settings.
+ * Furthermore, HVM guests are offered direct access, meaning that the
+ * values here may be stale in current context.
*/
uint32_t dr_mask[4];
};