[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] x86/msr: Handle MSR_AMD64_DR{0-3}_ADDRESS_MASK in the new MSR infrastructure



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@xxxxxxxxxx>
---
CC: Jan Beulich <JBeulich@xxxxxxxx>
CC: Wei Liu <wei.liu2@xxxxxxxxxx>
CC: Roger Pau Monné <roger.pau@xxxxxxxxxx>
CC: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
CC: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
CC: Brian Woods <brian.woods@xxxxxxx>

In the long run, I want to make a more generic infrastructure for
collecting/distributing MSR values which don't live in 'msrs'.  However, I
want to have several concrete usecases before attempting to design such an
infrastructure, which is why this patch is opencoded for now.
---
 xen/arch/x86/domctl.c          | 51 +++--------------------
 xen/arch/x86/hvm/hvm.c         |  6 +++
 xen/arch/x86/hvm/svm/svm.c     | 95 ------------------------------------------
 xen/arch/x86/msr.c             | 38 +++++++++++++++++
 xen/arch/x86/pv/emul-priv-op.c | 28 -------------
 xen/include/asm-x86/msr.h      |  5 ++-
 6 files changed, 54 insertions(+), 169 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 175a0c9..aa8ad19 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1274,6 +1274,10 @@ long arch_do_domctl(
         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);
 
@@ -1340,35 +1344,6 @@ long arch_do_domctl(
                     ++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 )
@@ -1398,24 +1373,10 @@ long arch_do_domctl(
                 {
                 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;
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 0bc676c..e2e4204 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1305,6 +1305,10 @@ static int hvm_load_cpu_xsave_states(struct domain *d, 
hvm_domain_context_t *h)
 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);
 
@@ -1438,6 +1442,8 @@ static int hvm_load_cpu_msrs(struct domain *d, 
hvm_domain_context_t *h)
 
         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 )
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 396ee4a..b9a8900 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -413,72 +413,6 @@ static int svm_load_vmcb_ctxt(struct vcpu *v, struct 
hvm_hw_cpu *ctxt)
     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;
@@ -2094,19 +2028,6 @@ static int svm_msr_read_intercept(unsigned int msr, 
uint64_t *msr_content)
             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 )
@@ -2292,19 +2213,6 @@ static int svm_msr_write_intercept(unsigned int msr, 
uint64_t msr_content)
          */
         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 )
@@ -2627,9 +2535,6 @@ static struct hvm_function_table __initdata 
svm_function_table = {
     .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,
diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c
index c9e87b1..76cb6ef 100644
--- a/xen/arch/x86/msr.c
+++ b/xen/arch/x86/msr.c
@@ -21,7 +21,10 @@
 
 #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);
@@ -159,6 +162,27 @@ int guest_rdmsr(const struct vcpu *v, uint32_t msr, 
uint64_t *val)
         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;
     }
@@ -285,6 +309,20 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val)
         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;
     }
diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c
index 83441b6..a84f3f1 100644
--- a/xen/arch/x86/pv/emul-priv-op.c
+++ b/xen/arch/x86/pv/emul-priv-op.c
@@ -912,18 +912,6 @@ static int read_msr(unsigned int reg, uint64_t *val,
         *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;
@@ -1106,22 +1094,6 @@ static int write_msr(unsigned int reg, uint64_t val,
             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:
diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h
index c1cb38f..05d905b 100644
--- a/xen/include/asm-x86/msr.h
+++ b/xen/include/asm-x86/msr.h
@@ -290,7 +290,10 @@ struct vcpu_msrs
 
     /*
      * 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];
 };
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.