]> xenbits.xensource.com Git - people/tklengyel/xen.git/commitdiff
xen/x86: Add XEN_DOMCTL_{rd/wr}msr_list hypercalls get_msrs2
authorTamas K Lengyel <tamas.lengyel@intel.com>
Thu, 22 Sep 2022 18:49:55 +0000 (18:49 +0000)
committerTamas K Lengyel <tamas.lengyel@intel.com>
Thu, 27 Oct 2022 17:48:22 +0000 (13:48 -0400)
Currently the XEN_DOMCTL_get_vcpu_msrs is only capable of gathering a handful
of predetermined vcpu MSRs. In our use-case gathering the vPMU MSRs by an
external privileged tool is necessary, thus we introduce a new set of domctls
to allow for querying for any guest MSRs.

Signed-off-by: Tamas K Lengyel <tamas.lengyel@intel.com>
---
wrmsr and AMD side totally unimplemented
still needs wiring into guest_{rd/wr}msr

12 files changed:
tools/include/xenctrl.h
tools/libs/ctrl/xc_domain.c
xen/arch/x86/cpu/vpmu.c
xen/arch/x86/cpu/vpmu_amd.c
xen/arch/x86/cpu/vpmu_intel.c
xen/arch/x86/domctl.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/include/asm/vpmu.h
xen/arch/x86/msr.c
xen/arch/x86/pv/emul-priv-op.c
xen/include/public/domctl.h

index 0c8b4c3aa7a5f639c314e14dfb40e75782186e25..01a39f6dd41596a696f0d969b06c43cd91ca5f8c 100644 (file)
@@ -872,6 +872,12 @@ int xc_vcpu_getinfo(xc_interface *xch,
                     uint32_t vcpu,
                     xc_vcpuinfo_t *info);
 
+typedef struct xen_domctl_vcpu_msr xc_vcpumsr_t;
+int xc_vcpu_rdmsr_list(xc_interface *xch, uint32_t domid, uint32_t vcpu,
+                       uint32_t count, xc_vcpumsr_t *msrs);
+int xc_vcpu_wrmsr_list(xc_interface *xch, uint32_t domid, uint32_t vcpu,
+                       uint32_t count, xc_vcpumsr_t *msrs);
+
 long long xc_domain_get_cpu_usage(xc_interface *xch,
                                   uint32_t domid,
                                   int vcpu);
index 14c0420c35be5a0a9a2776a7007d413b272a6050..7e84ab12726e3d8372093c30a76c8d98020c15e1 100644 (file)
@@ -2201,6 +2201,57 @@ int xc_domain_soft_reset(xc_interface *xch,
     domctl.domain = domid;
     return do_domctl(xch, &domctl);
 }
+
+int xc_vcpu_rdmsr_list(xc_interface *xch, uint32_t domid, uint32_t vcpu,
+                       uint32_t count, xc_vcpumsr_t *msrs)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    DECLARE_HYPERCALL_BOUNCE(msrs, count * sizeof(xc_vcpumsr_t), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
+
+    if ( !count || !msrs )
+        return -1;
+
+    domctl.cmd = XEN_DOMCTL_rdmsr_list;
+    domctl.domain = domid;
+    domctl.u.vcpu_msrs.vcpu = vcpu;
+    domctl.u.vcpu_msrs.msr_count = count;
+
+    if ( xc_hypercall_bounce_pre(xch, msrs) )
+        return -ENOMEM;
+
+    set_xen_guest_handle(domctl.u.vcpu_msrs.msrs, msrs);
+    rc = do_domctl(xch, &domctl);
+    xc_hypercall_bounce_post(xch, msrs);
+
+    return rc;
+}
+
+int xc_vcpu_wrmsr_list(xc_interface *xch, uint32_t domid, uint32_t vcpu,
+                       uint32_t count, xc_vcpumsr_t *msrs)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    DECLARE_HYPERCALL_BOUNCE(msrs, count * sizeof(xc_vcpumsr_t), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
+
+    if ( !count || !msrs )
+        return -1;
+
+    domctl.cmd = XEN_DOMCTL_wrmsr_list;
+    domctl.domain = domid;
+    domctl.u.vcpu_msrs.vcpu = vcpu;
+    domctl.u.vcpu_msrs.msr_count = count;
+
+    if ( xc_hypercall_bounce_pre(xch, msrs) )
+        return -ENOMEM;
+
+    set_xen_guest_handle(domctl.u.vcpu_msrs.msrs, msrs);
+    rc = do_domctl(xch, &domctl);
+    xc_hypercall_bounce_post(xch, msrs);
+
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
index 64cdbfc48c4b67b5b41cb1daf8100d88799891b3..8139260667067473c7bf4cae4aab6c27ff64443b 100644 (file)
@@ -117,9 +117,8 @@ void vpmu_lvtpc_update(uint32_t val)
         apic_write(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
 }
 
-int vpmu_do_msr(unsigned int msr, uint64_t *msr_content, bool is_write)
+int vpmu_do_msr(struct vcpu *v, unsigned int msr, uint64_t *msr_content, bool is_write)
 {
-    struct vcpu *curr = current;
     struct vpmu_struct *vpmu;
     int ret = 0;
 
@@ -129,10 +128,10 @@ int vpmu_do_msr(unsigned int msr, uint64_t *msr_content, bool is_write)
      */
     if ( likely(vpmu_mode == XENPMU_MODE_OFF) ||
          ((vpmu_mode & XENPMU_MODE_ALL) &&
-          !is_hardware_domain(curr->domain)) )
+          !is_hardware_domain(v->domain)) )
          goto nop;
 
-    vpmu = vcpu_vpmu(curr);
+    vpmu = vcpu_vpmu(v);
     if ( !vpmu_is_set(vpmu, VPMU_INITIALIZED) )
         goto nop;
 
@@ -146,7 +145,7 @@ int vpmu_do_msr(unsigned int msr, uint64_t *msr_content, bool is_write)
      * and since do_wr/rdmsr may load VPMU context we should save
      * (and unload) it again.
      */
-    if ( !has_vlapic(curr->domain) && vpmu->xenpmu_data &&
+    if ( !has_vlapic(v->domain) && vpmu->xenpmu_data &&
         vpmu_is_set(vpmu, VPMU_CACHED) )
     {
         vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
index 58794a16f06cd4041935922a51eb813a364a5d14..0f16fa9a43ad038d8cb360267c98cf21354bb2d3 100644 (file)
@@ -350,11 +350,12 @@ static void context_update(unsigned int msr, u64 msr_content)
 
 static int cf_check amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
 {
-    struct vcpu *v = current;
     struct vpmu_struct *vpmu = vcpu_vpmu(v);
     unsigned int idx = 0;
     int type = get_pmu_reg_type(msr, &idx);
 
+    ASSERT(v == current);
+
     if ( (type == MSR_TYPE_CTRL ) &&
          ((msr_content & CTRL_RSVD_MASK) != ctrl_rsvd[idx]) )
         return -EINVAL;
@@ -404,11 +405,13 @@ static int cf_check amd_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
     return 0;
 }
 
-static int cf_check amd_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
+static int cf_check amd_vpmu_do_rdmsr(struct vcpu *v, unsigned int msr,
+                                      uint64_t *msr_content)
 {
-    struct vcpu *v = current;
     struct vpmu_struct *vpmu = vcpu_vpmu(v);
 
+    ASSERT(v == current);
+
     if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)
         || vpmu_is_set(vpmu, VPMU_FROZEN) )
     {
@@ -518,6 +521,12 @@ static int cf_check svm_vpmu_initialise(struct vcpu *v)
     return 0;
 }
 
+static int cf_check amd_get_msr(struct vcpu *v, unsigned int msr, uint64_t *val)
+{
+    /* TODO in case an external tool needs access to these MSRs */
+    return -ENOSYS;
+}
+
 #ifdef CONFIG_MEM_SHARING
 static int cf_check amd_allocate_context(struct vcpu *v)
 {
@@ -535,6 +544,7 @@ static const struct arch_vpmu_ops __initconst_cf_clobber amd_vpmu_ops = {
     .arch_vpmu_save = amd_vpmu_save,
     .arch_vpmu_load = amd_vpmu_load,
     .arch_vpmu_dump = amd_vpmu_dump,
+    .get_msr = amd_get_msr,
 
 #ifdef CONFIG_MEM_SHARING
     .allocate_context = amd_allocate_context,
index b91d818be0b6a81b63b1c01c44e4f1011820bf6b..331335b61cde47076b9f84c46406e14e74012dd7 100644 (file)
@@ -540,15 +540,20 @@ static int core2_vpmu_msr_common_check(u32 msr_index, int *type, int *index)
     return 1;
 }
 
-static int cf_check core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
+static int cf_check core2_vpmu_do_wrmsr(struct vcpu *v, unsigned int msr, uint64_t msr_content)
 {
     int i, tmp;
     int type = -1, index = -1;
-    struct vcpu *v = current;
     struct vpmu_struct *vpmu = vcpu_vpmu(v);
     struct xen_pmu_intel_ctxt *core2_vpmu_cxt;
     uint64_t *enabled_cntrs;
 
+    if ( v != current )
+    {
+        gdprintk(XENLOG_INFO, "Not yet implemented\n");
+        return -ENOSYS;
+    }
+
     if ( !core2_vpmu_msr_common_check(msr, &type, &index) )
         return -EINVAL;
 
@@ -708,13 +713,46 @@ static int cf_check core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
     return 0;
 }
 
-static int cf_check core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
+static int cf_check get_saved_msr(struct vcpu *v, unsigned int msr, uint64_t *val)
+{
+    int type, index, ret = 0;
+    struct vpmu_struct *vpmu = vcpu_vpmu(v);
+    struct xen_pmu_intel_ctxt *core2_vpmu_cxt = vpmu->context;
+    uint64_t *fixed_counters = vpmu_reg_pointer(core2_vpmu_cxt, fixed_counters);
+    struct xen_pmu_cntr_pair *xen_pmu_cntr_pair =
+        vpmu_reg_pointer(core2_vpmu_cxt, arch_counters);
+
+    if ( !is_core2_vpmu_msr(msr, &type, &index) )
+        return -EINVAL;
+
+    if ( msr == MSR_CORE_PERF_GLOBAL_OVF_CTRL )
+        *val = core2_vpmu_cxt->global_ovf_ctrl;
+    else if ( msr == MSR_CORE_PERF_GLOBAL_STATUS )
+        *val = core2_vpmu_cxt->global_status;
+    else if ( msr == MSR_CORE_PERF_GLOBAL_CTRL )
+        *val = core2_vpmu_cxt->global_ctrl;
+    else if ( msr >= MSR_CORE_PERF_FIXED_CTR0 &&
+              msr < MSR_CORE_PERF_FIXED_CTR0 + fixed_pmc_cnt )
+        *val = fixed_counters[msr - MSR_CORE_PERF_FIXED_CTR0];
+    else if ( msr >= MSR_P6_PERFCTR(0) && msr < MSR_P6_PERFCTR(arch_pmc_cnt) )
+        *val = xen_pmu_cntr_pair[msr - MSR_P6_PERFCTR(0)].counter;
+    else if ( msr >= MSR_P6_EVNTSEL(0) && msr < MSR_P6_EVNTSEL(arch_pmc_cnt) )
+        *val = xen_pmu_cntr_pair[msr - MSR_P6_EVNTSEL(0)].control;
+    else
+        ret = -EINVAL;
+
+    return ret;
+}
+
+static int cf_check core2_vpmu_do_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
 {
     int type = -1, index = -1;
-    struct vcpu *v = current;
     struct vpmu_struct *vpmu = vcpu_vpmu(v);
     struct xen_pmu_intel_ctxt *core2_vpmu_cxt;
 
+    if ( v != current )
+        return get_saved_msr(v, msr, msr_content);
+
     if ( core2_vpmu_msr_common_check(msr, &type, &index) )
     {
         core2_vpmu_cxt = vpmu->context;
index e9bfbc57a794ee139c3b5761378f15eb20cb1c8e..0c52bab511d3964f5b270911045ab348510a9043 100644 (file)
@@ -1081,6 +1081,63 @@ long arch_do_domctl(
         break;
     }
 
+    case XEN_DOMCTL_rdmsr_list:
+    case XEN_DOMCTL_wrmsr_list:
+    {
+        struct xen_domctl_vcpu_msrs *vmsrs = &domctl->u.vcpu_msrs;
+        struct xen_domctl_vcpu_msr msr = {};
+        struct vcpu *v;
+        unsigned int i;
+
+        ret = -ESRCH;
+        if ( (vmsrs->vcpu >= d->max_vcpus) ||
+             ((v = d->vcpu[vmsrs->vcpu]) == NULL) )
+            break;
+
+        ret = -EINVAL;
+        if ( v == curr ) /* no vcpu_pause() */
+            break;
+
+        if ( !vmsrs->msr_count || guest_handle_is_null(vmsrs->msrs) )
+            break;
+
+        vcpu_pause(v);
+
+        ret = 0;
+        for ( i=0; i<vmsrs->msr_count; i++ )
+        {
+            int rc;
+
+            if ( copy_from_guest_offset(&msr, vmsrs->msrs, i, 1) )
+            {
+                ret = -EFAULT;
+                break;
+            }
+
+            if ( domctl->cmd == XEN_DOMCTL_rdmsr_list )
+                rc = guest_rdmsr(v, msr.index, &msr.value);
+            else
+                rc = guest_wrmsr(v, msr.index, msr.value);
+
+            if ( rc != X86EMUL_OKAY )
+            {
+                ret = -EINVAL;
+                vmsrs->msr_count = i;
+                copyback = true;
+                break;
+            }
+
+            if ( copy_to_guest_offset(vmsrs->msrs, i, &msr, 1)
+            {
+                ret = -EFAULT;
+                break;
+            }
+        }
+
+        vcpu_unpause(v);
+        break;
+    }
+
     case XEN_DOMCTL_get_vcpu_msrs:
     case XEN_DOMCTL_set_vcpu_msrs:
     {
index 1aeaabcb13fcbd343f731fa89c09ab74a59f47ac..44ab4f6ceba1b16505c4d0ba29ddcab0adc92bc0 100644 (file)
@@ -1952,7 +1952,7 @@ static int cf_check svm_msr_read_intercept(
     case MSR_AMD_FAM15H_EVNTSEL3:
     case MSR_AMD_FAM15H_EVNTSEL4:
     case MSR_AMD_FAM15H_EVNTSEL5:
-        if ( vpmu_do_rdmsr(msr, msr_content) )
+        if ( vpmu_do_rdmsr(v, msr, msr_content) )
             goto gpf;
         break;
 
index 17e103188a53edbd55dd1cd7a505c32da6459e5f..d38e68e4bcd63783adf051574d8fb965e3632488 100644 (file)
@@ -3295,7 +3295,7 @@ static int cf_check vmx_msr_read_intercept(
     case MSR_CORE_PERF_FIXED_CTR_CTRL...MSR_CORE_PERF_GLOBAL_OVF_CTRL:
     case MSR_IA32_PEBS_ENABLE:
     case MSR_IA32_DS_AREA:
-        if ( vpmu_do_rdmsr(msr, msr_content) )
+        if ( vpmu_do_rdmsr(curr, msr, msr_content) )
             goto gp_fault;
         break;
 
index 05e1fbfccfcf9f592108a8db70f7955e52129cca..ca51b3bbecace4fdb1c69f18f376d60e58d8f550 100644 (file)
@@ -40,8 +40,8 @@
 /* Arch specific operations shared by all vpmus */
 struct arch_vpmu_ops {
     int (*initialise)(struct vcpu *v);
-    int (*do_wrmsr)(unsigned int msr, uint64_t msr_content);
-    int (*do_rdmsr)(unsigned int msr, uint64_t *msr_content);
+    int (*do_wrmsr)(struct vcpu *v, unsigned int msr, uint64_t msr_content);
+    int (*do_rdmsr)(struct vcpu *v, unsigned int msr, uint64_t *msr_content);
     int (*do_interrupt)(struct cpu_user_regs *regs);
     void (*arch_vpmu_destroy)(struct vcpu *v);
     int (*arch_vpmu_save)(struct vcpu *v, bool_t to_guest);
@@ -109,7 +109,7 @@ static inline bool_t vpmu_are_all_set(const struct vpmu_struct *vpmu,
 }
 
 void vpmu_lvtpc_update(uint32_t val);
-int vpmu_do_msr(unsigned int msr, uint64_t *msr_content, bool is_write);
+int vpmu_do_msr(struct vcpu *v, unsigned int msr, uint64_t *msr_content, bool is_write);
 void vpmu_do_interrupt(struct cpu_user_regs *regs);
 void vpmu_initialise(struct vcpu *v);
 void vpmu_destroy(struct vcpu *v);
@@ -118,13 +118,13 @@ void cf_check vpmu_save_force(void *arg);
 int vpmu_load(struct vcpu *v, bool_t from_guest);
 void vpmu_dump(struct vcpu *v);
 
-static inline int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
+static inline int vpmu_do_wrmsr(struct vcpu *v, unsigned int msr, uint64_t msr_content)
 {
-    return vpmu_do_msr(msr, &msr_content, true /* write */);
+    return vpmu_do_msr(v, msr, &msr_content, true /* write */);
 }
-static inline int vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
+static inline int vpmu_do_rdmsr(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
 {
-    return vpmu_do_msr(msr, msr_content, false /* read */);
+    return vpmu_do_msr(v, msr, msr_content, false /* read */);
 }
 
 extern unsigned int vpmu_mode;
index 95416995a5ab185fd3bbb62d99b8da2cd0300bdd..9b487a0ae85b20bdda4f2a040a087d651e5035aa 100644 (file)
@@ -431,6 +431,7 @@ int guest_rdmsr(struct vcpu *v, uint32_t msr, uint64_t *val)
     case MSR_INTEL_CORE_THREAD_COUNT:
          */
     default:
+        /* TODO: vpmu msrs for external tools should get wired in here */
         return X86EMUL_UNHANDLEABLE;
     }
 
index 5da00e24e4ff15a9ef61c10002a3e511fced799c..cfb7c665fdcd2d6abc4688b8df3eb364b1f7b5d4 100644 (file)
@@ -992,7 +992,7 @@ static int cf_check read_msr(
             if ( vpmu_msr || (boot_cpu_data.x86_vendor &
                               (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
             {
-                if ( vpmu_do_rdmsr(reg, val) )
+                if ( vpmu_do_rdmsr(curr, reg, val) )
                     break;
                 return X86EMUL_OKAY;
             }
index b2ae839c36321772e01a66cfd12ce8d3730f5567..01eb8150e62030170c5c3f4e077135bc11708f67 100644 (file)
@@ -971,6 +971,20 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpu_msr_t);
  * Output for set:
  * - If Xen encounters an error with a specific MSR, -EINVAL shall be returned
  *   and 'msr_count' shall be set to the offending index, to aid debugging.
+ *
+*/
+/*
+ * XEN_DOMCTL_rdmsr_list / XEN_DOMCTL_wrmsr_list.
+ *
+ * Input:
+ * - 'msr_count' is the number of entries in 'msrs'.
+ *
+ * Output:
+ * - If Xen encounters an error with a specific MSR, including an MSR that's
+ *   unused by the guest, -EINVAL shall be returned and 'msr_count' shall be
+ *   set to the offending index, to aid debugging. The remaining items in the
+ *   list after the offending MSR remain unprocessed by Xen.
+ *
  */
 struct xen_domctl_vcpu_msrs {
     uint32_t vcpu;                                   /* IN     */
@@ -1274,6 +1288,8 @@ struct xen_domctl {
 #define XEN_DOMCTL_get_cpu_policy                82
 #define XEN_DOMCTL_set_cpu_policy                83
 #define XEN_DOMCTL_vmtrace_op                    84
+#define XEN_DOMCTL_rdmsr_list                    85
+#define XEN_DOMCTL_wrmsr_list                    86
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002