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

[Xen-devel] [PATCH V4 08/13] xen: Introduce monitor_op domctl



In preparation for allowing for introspecting ARM and PV domains the old
control interface via the hvm_op hypercall is retired. A new control mechanism
is introduced via the domctl hypercall: monitor_op.

This patch aims to establish a base API on which future applications can build
on.

Suggested-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Signed-off-by: Tamas K Lengyel <tamas.lengyel@xxxxxxxxxxxx>
Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
Acked-by: Kevin Tian <kevin.tian@xxxxxxxxx>
---
v4: Style fixes
    Only defining struct mov_to_cr and struct debug_event in asm-x86/domain.h
    Add pause/unpause domain wrapper when enabled a monitor option.
---
 tools/libxc/Makefile                |   1 +
 tools/libxc/include/xenctrl.h       |  19 ++++
 tools/libxc/xc_mem_access.c         |   9 +-
 tools/libxc/xc_monitor.c            | 118 +++++++++++++++++++++
 tools/libxc/xc_private.h            |   2 +-
 tools/libxc/xc_vm_event.c           |   7 +-
 tools/tests/xen-access/xen-access.c |  14 +--
 xen/arch/x86/Makefile               |   1 +
 xen/arch/x86/hvm/emulate.c          |   3 +-
 xen/arch/x86/hvm/event.c            |  69 ++++++------
 xen/arch/x86/hvm/hvm.c              |  38 +------
 xen/arch/x86/hvm/vmx/vmcs.c         |   6 +-
 xen/arch/x86/hvm/vmx/vmx.c          |   2 +-
 xen/arch/x86/mm/p2m.c               |   9 --
 xen/arch/x86/monitor.c              | 204 ++++++++++++++++++++++++++++++++++++
 xen/common/domctl.c                 |   9 ++
 xen/common/vm_event.c               |  19 +---
 xen/include/asm-arm/monitor.h       |  13 +++
 xen/include/asm-x86/domain.h        |  28 +++++
 xen/include/asm-x86/hvm/domain.h    |   1 -
 xen/include/asm-x86/monitor.h       |   8 ++
 xen/include/public/domctl.h         |  50 ++++++++-
 xen/include/public/hvm/params.h     |  15 ---
 xen/include/public/vm_event.h       |   2 +-
 xen/xsm/flask/hooks.c               |   3 +
 xen/xsm/flask/policy/access_vectors |   2 +
 26 files changed, 510 insertions(+), 142 deletions(-)
 create mode 100644 tools/libxc/xc_monitor.c
 create mode 100644 xen/arch/x86/monitor.c
 create mode 100644 xen/include/asm-arm/monitor.h
 create mode 100644 xen/include/asm-x86/monitor.h

diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 22ba2a1..8b609cf 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -32,6 +32,7 @@ CTRL_SRCS-y       += xc_cpu_hotplug.c
 CTRL_SRCS-y       += xc_resume.c
 CTRL_SRCS-y       += xc_tmem.c
 CTRL_SRCS-y       += xc_vm_event.c
+CTRL_SRCS-y       += xc_monitor.c
 CTRL_SRCS-y       += xc_mem_paging.c
 CTRL_SRCS-y       += xc_mem_access.c
 CTRL_SRCS-y       += xc_memshr.c
diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 790db53..3324132 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2308,6 +2308,25 @@ int xc_get_mem_access(xc_interface *xch, domid_t 
domain_id,
                       uint64_t pfn, xenmem_access_t *access);
 
 /***
+ * Monitor control operations.
+ */
+int xc_monitor_mov_to_cr0(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly);
+int xc_monitor_mov_to_cr3(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly);
+int xc_monitor_mov_to_cr4(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly);
+int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int extended_capture);
+int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id,
+                          unsigned int op);
+int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
+                                   unsigned int op);
+
+/***
  * Memory sharing operations.
  *
  * Unles otherwise noted, these calls return 0 on succes, -1 and errno on
diff --git a/tools/libxc/xc_mem_access.c b/tools/libxc/xc_mem_access.c
index 0a3f0e6..37e776c 100644
--- a/tools/libxc/xc_mem_access.c
+++ b/tools/libxc/xc_mem_access.c
@@ -27,14 +27,7 @@
 void *xc_mem_access_enable(xc_interface *xch, domid_t domain_id, uint32_t 
*port)
 {
     return xc_vm_event_enable(xch, domain_id, HVM_PARAM_MONITOR_RING_PFN,
-                              port, 0);
-}
-
-void *xc_mem_access_enable_introspection(xc_interface *xch, domid_t domain_id,
-                                         uint32_t *port)
-{
-    return xc_vm_event_enable(xch, domain_id, HVM_PARAM_MONITOR_RING_PFN,
-                              port, 1);
+                              port);
 }
 
 int xc_mem_access_disable(xc_interface *xch, domid_t domain_id)
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
new file mode 100644
index 0000000..9e807d1
--- /dev/null
+++ b/tools/libxc/xc_monitor.c
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * xc_monitor.c
+ *
+ * Interface to VM event monitor
+ *
+ * Copyright (c) 2015 Tamas K Lengyel (tamas@xxxxxxxxxxxxx)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ */
+
+#include "xc_private.h"
+
+int xc_monitor_mov_to_cr0(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR0;
+    domctl.u.monitor_op.u.mov_to_cr.sync = sync;
+    domctl.u.monitor_op.u.mov_to_cr.onchangeonly = onchangeonly;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_mov_to_cr3(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR3;
+    domctl.u.monitor_op.u.mov_to_cr.sync = sync;
+    domctl.u.monitor_op.u.mov_to_cr.onchangeonly = onchangeonly;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_mov_to_cr4(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int sync,
+                          unsigned int onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR4;
+    domctl.u.monitor_op.u.mov_to_cr.sync = sync;
+    domctl.u.monitor_op.u.mov_to_cr.onchangeonly = onchangeonly;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id,
+                          unsigned int op, unsigned int extended_capture)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_MSR;
+    domctl.u.monitor_op.u.mov_to_msr.extended_capture = extended_capture;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
+                                   unsigned int op)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_SOFTWARE_BREAKPOINT;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id,
+                          unsigned int op)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = op ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.subop = XEN_DOMCTL_MONITOR_SUBOP_SINGLESTEP;
+
+    return do_domctl(xch, &domctl);
+}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 843540c..9f55309 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -430,6 +430,6 @@ int xc_vm_event_control(xc_interface *xch, domid_t 
domain_id, unsigned int op,
  * param can be HVM_PARAM_PAGING/ACCESS/SHARING_RING_PFN
  */
 void *xc_vm_event_enable(xc_interface *xch, domid_t domain_id, int param,
-                         uint32_t *port, int enable_introspection);
+                         uint32_t *port);
 
 #endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vm_event.c b/tools/libxc/xc_vm_event.c
index d458b9a..7277e86 100644
--- a/tools/libxc/xc_vm_event.c
+++ b/tools/libxc/xc_vm_event.c
@@ -41,7 +41,7 @@ int xc_vm_event_control(xc_interface *xch, domid_t domain_id, 
unsigned int op,
 }
 
 void *xc_vm_event_enable(xc_interface *xch, domid_t domain_id, int param,
-                         uint32_t *port, int enable_introspection)
+                         uint32_t *port)
 {
     void *ring_page = NULL;
     uint64_t pfn;
@@ -104,10 +104,7 @@ void *xc_vm_event_enable(xc_interface *xch, domid_t 
domain_id, int param,
         break;
 
     case HVM_PARAM_MONITOR_RING_PFN:
-        if ( enable_introspection )
-            op = XEN_VM_EVENT_MONITOR_ENABLE_INTROSPECTION;
-        else
-            op = XEN_VM_EVENT_MONITOR_ENABLE;
+        op = XEN_VM_EVENT_MONITOR_ENABLE;
         mode = XEN_DOMCTL_VM_EVENT_OP_MONITOR;
         break;
 
diff --git a/tools/tests/xen-access/xen-access.c 
b/tools/tests/xen-access/xen-access.c
index fe1589e..0d1bf78 100644
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -447,13 +447,13 @@ int main(int argc, char *argv[])
     }
 
     if ( int3 )
-        rc = xc_hvm_param_set(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, 
HVMPME_mode_sync);
-    else
-        rc = xc_hvm_param_set(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, 
HVMPME_mode_disabled);
-    if ( rc < 0 )
     {
-        ERROR("Error %d setting int3 vm_event\n", rc);
-        goto exit;
+        rc = xc_monitor_software_breakpoint(xch, domain_id, 1);
+        if ( rc < 0 )
+        {
+            ERROR("Error %d setting int3 vm_event\n", rc);
+            goto exit;
+        }
     }
 
     /* Wait for access */
@@ -467,7 +467,7 @@ int main(int argc, char *argv[])
             rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, ~0ull, 
0);
             rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, 0,
                                    xenaccess->domain_info->max_pages);
-            rc = xc_hvm_param_set(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, 
HVMPME_mode_disabled);
+            rc = xc_monitor_software_breakpoint(xch, domain_id, 0);
 
             shutting_down = 1;
         }
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 86ca5f8..37e547c 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -36,6 +36,7 @@ obj-y += microcode_intel.o
 # This must come after the vendor specific files.
 obj-y += microcode.o
 obj-y += mm.o
+obj-y += monitor.o
 obj-y += mpparse.o
 obj-y += nmi.o
 obj-y += numa.o
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index fa7175a..6177ca9 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -411,7 +411,8 @@ static int hvmemul_virtual_to_linear(
      * being triggered for repeated writes to a whole page.
      */
     *reps = min_t(unsigned long, *reps,
-                  
unlikely(current->domain->arch.hvm_domain.introspection_enabled)
+                  unlikely(current->domain->arch
+                            .monitor_options.mov_to_msr.extended_capture)
                            ? 1 : 4096);
 
     reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
diff --git a/xen/arch/x86/hvm/event.c b/xen/arch/x86/hvm/event.c
index f3919b0..95f4311 100644
--- a/xen/arch/x86/hvm/event.c
+++ b/xen/arch/x86/hvm/event.c
@@ -55,15 +55,12 @@ static void hvm_event_fill_regs(vm_event_request_t *req)
     req->regs.x86.cr4 = curr->arch.hvm_vcpu.guest_cr[4];
 }
 
-static int hvm_event_traps(long parameters, vm_event_request_t *req)
+static int hvm_event_traps(uint8_t sync, vm_event_request_t *req)
 {
     int rc;
     struct vcpu *curr = current;
     struct domain *currd = curr->domain;
 
-    if ( !(parameters & HVMPME_MODE_MASK) )
-        return 0;
-
     rc = vm_event_claim_slot(currd, &currd->vm_event->monitor);
     switch ( rc )
     {
@@ -79,7 +76,7 @@ static int hvm_event_traps(long parameters, 
vm_event_request_t *req)
         return rc;
     };
 
-    if ( (parameters & HVMPME_MODE_MASK) == HVMPME_mode_sync )
+    if ( sync )
     {
         req->flags |= VM_EVENT_FLAG_VCPU_PAUSED;
         vm_event_vcpu_pause(curr);
@@ -92,7 +89,7 @@ static int hvm_event_traps(long parameters, 
vm_event_request_t *req)
 }
 
 static void hvm_event_cr(uint32_t reason, unsigned long value,
-                                unsigned long old)
+                         unsigned long old, struct mov_to_cr *option)
 {
     vm_event_request_t req = {
         .reason = reason,
@@ -100,43 +97,38 @@ static void hvm_event_cr(uint32_t reason, unsigned long 
value,
         .u.mov_to_cr.new_value = value,
         .u.mov_to_cr.old_value = old
     };
-    uint64_t parameters = 0;
-
-    switch(reason)
-    {
-    case VM_EVENT_REASON_MOV_TO_CR0:
-        parameters = current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR0];
-        break;
-    case VM_EVENT_REASON_MOV_TO_CR3:
-        parameters = current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR3];
-        break;
-    case VM_EVENT_REASON_MOV_TO_CR4:
-        parameters = current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR4];
-        break;
-    };
 
-    if ( (parameters & HVMPME_onchangeonly) && (value == old) )
+    if ( option->onchangeonly && value == old )
         return;
 
-    hvm_event_traps(parameters, &req);
+    hvm_event_traps(option->sync, &req);
 }
 
 void hvm_event_cr0(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR0, value, old);
+    struct domain *currd = current->domain;
+
+    if ( currd->arch.monitor_options.mov_to_cr0.enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR0, value, old,
+                     &currd->arch.monitor_options.mov_to_cr0);
 }
 
 void hvm_event_cr3(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR3, value, old);
+    struct domain *currd = current->domain;
+
+    if ( currd->arch.monitor_options.mov_to_cr3.enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR3, value, old,
+                     &currd->arch.monitor_options.mov_to_cr3);
 }
 
 void hvm_event_cr4(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR4, value, old);
+    struct domain *currd = current->domain;
+
+    if ( currd->arch.monitor_options.mov_to_cr4.enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR4, value, old,
+                     &currd->arch.monitor_options.mov_to_cr4);
 }
 
 void hvm_event_msr(unsigned long msr, unsigned long value)
@@ -148,14 +140,14 @@ void hvm_event_msr(unsigned long msr, unsigned long value)
         .u.mov_to_msr.msr = msr,
         .u.mov_to_msr.value = value,
     };
-    long params = current->domain->arch.hvm_domain
-                    .params[HVM_PARAM_MEMORY_EVENT_MSR];
 
-    hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor_options.mov_to_msr.enabled )
+        hvm_event_traps(1, &req);
 }
 
 int hvm_event_int3(unsigned long gla)
 {
+    int rc = 0;
     uint32_t pfec = PFEC_page_present;
     struct vcpu *curr = current;
     vm_event_request_t req = {
@@ -163,14 +155,16 @@ int hvm_event_int3(unsigned long gla)
         .vcpu_id = curr->vcpu_id,
         .u.software_breakpoint.gfn = paging_gva_to_gfn(curr, gla, &pfec)
     };
-    long params = curr->domain->arch.hvm_domain
-                    .params[HVM_PARAM_MEMORY_EVENT_INT3];
 
-    return hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor_options.software_breakpoint.enabled )
+        rc = hvm_event_traps(1, &req);
+
+    return rc;
 }
 
 int hvm_event_single_step(unsigned long gla)
 {
+    int rc = 0;
     uint32_t pfec = PFEC_page_present;
     struct vcpu *curr = current;
     vm_event_request_t req = {
@@ -178,10 +172,11 @@ int hvm_event_single_step(unsigned long gla)
         .vcpu_id = curr->vcpu_id,
         .u.singlestep.gfn = paging_gva_to_gfn(curr, gla, &pfec)
     };
-    long params = curr->domain->arch.hvm_domain
-                    .params[HVM_PARAM_MEMORY_EVENT_SINGLE_STEP];
 
-    return hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor_options.singlestep.enabled )
+        rc = hvm_event_traps(1, &req);
+
+    return rc;
 }
 
 /*
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index ea8a82d..3210264 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5783,23 +5783,6 @@ long do_hvm_op(unsigned long op, 
XEN_GUEST_HANDLE_PARAM(void) arg)
             case HVM_PARAM_ACPI_IOPORTS_LOCATION:
                 rc = pmtimer_change_ioport(d, a.value);
                 break;
-            case HVM_PARAM_MEMORY_EVENT_CR0:
-            case HVM_PARAM_MEMORY_EVENT_CR3:
-            case HVM_PARAM_MEMORY_EVENT_CR4:
-                if ( d == current->domain )
-                    rc = -EPERM;
-                break;
-            case HVM_PARAM_MEMORY_EVENT_INT3:
-            case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
-            case HVM_PARAM_MEMORY_EVENT_MSR:
-                if ( d == current->domain )
-                {
-                    rc = -EPERM;
-                    break;
-                }
-                if ( a.value & HVMPME_onchangeonly )
-                    rc = -EINVAL;
-                break;
             case HVM_PARAM_NESTEDHVM:
                 rc = xsm_hvm_param_nested(XSM_PRIV, d);
                 if ( rc )
@@ -5858,29 +5841,10 @@ long do_hvm_op(unsigned long op, 
XEN_GUEST_HANDLE_PARAM(void) arg)
             }
             }
 
-            if ( rc == 0 ) 
+            if ( rc == 0 )
             {
                 d->arch.hvm_domain.params[a.index] = a.value;
-
-                switch( a.index )
-                {
-                case HVM_PARAM_MEMORY_EVENT_INT3:
-                case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
-                {
-                    domain_pause(d);
-                    domain_unpause(d); /* Causes guest to latch new status */
-                    break;
-                }
-                case HVM_PARAM_MEMORY_EVENT_CR3:
-                {
-                    for_each_vcpu ( d, v )
-                        hvm_funcs.update_guest_cr(v, 0); /* Latches new CR3 
mask through CR0 code */
-                    break;
-                }
-                }
-
             }
-
         }
         else
         {
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 63007a9..17b2ab0 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -714,7 +714,7 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, 
int type)
     if ( msr_bitmap == NULL )
         return;
 
-    if ( unlikely(d->arch.hvm_domain.introspection_enabled) &&
+    if ( unlikely(d->arch.monitor_options.mov_to_msr.extended_capture) &&
          vm_event_check_ring(&d->vm_event->monitor) )
     {
         unsigned int i;
@@ -1373,8 +1373,8 @@ void vmx_do_resume(struct vcpu *v)
     }
 
     debug_state = v->domain->debugger_attached
-                  || 
v->domain->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_INT3]
-                  || 
v->domain->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_SINGLE_STEP];
+                  || 
v->domain->arch.monitor_options.software_breakpoint.enabled
+                  || v->domain->arch.monitor_options.singlestep.enabled;
 
     if ( unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 3f2a18f..fcd25df 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1232,7 +1232,7 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned 
int cr)
                 v->arch.hvm_vmx.exec_control |= cr3_ctls;
 
             /* Trap CR3 updates if CR3 memory events are enabled. */
-            if ( v->domain->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_CR3] 
)
+            if ( v->domain->arch.monitor_options.mov_to_cr3.enabled )
                 v->arch.hvm_vmx.exec_control |= CPU_BASED_CR3_LOAD_EXITING;
 
             vmx_update_cpu_exec_control(v);
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index db332ef..38defdf 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1451,15 +1451,6 @@ void p2m_vm_event_emulate_check(struct vcpu *v, const 
vm_event_response_t *rsp)
     }
 }
 
-void p2m_setup_introspection(struct domain *d)
-{
-    if ( hvm_funcs.enable_msr_exit_interception )
-    {
-        d->arch.hvm_domain.introspection_enabled = 1;
-        hvm_funcs.enable_msr_exit_interception(d);
-    }
-}
-
 bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
                             struct npfec npfec,
                             vm_event_request_t **req_ptr)
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
new file mode 100644
index 0000000..7bfab64
--- /dev/null
+++ b/xen/arch/x86/monitor.c
@@ -0,0 +1,204 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <xen/mm.h>
+#include <asm/domain.h>
+
+#define DISABLE_OPTION(option)              \
+    do {                                    \
+        if ( !option->enabled )             \
+            return -EFAULT;                 \
+        domain_pause(d);                    \
+        option->enabled = 0;                \
+        domain_unpause(d);                  \
+    } while (0)
+
+#define ENABLE_OPTION(option)               \
+    do {                                    \
+        domain_pause(d);                    \
+        option->enabled = 1;                \
+        domain_unpause(d);                  \
+    } while (0)
+
+int monitor_domctl(struct xen_domctl_monitor_op *domctl, struct domain *d)
+{
+    /*
+     * At the moment only HVM domains are supported. However, event delivery
+     * could be extended to PV domains. See comments below.
+     */
+    if ( !is_hvm_domain(d) )
+        return -ENOSYS;
+
+    if ( domctl->op != XEN_DOMCTL_MONITOR_OP_ENABLE &&
+         domctl->op != XEN_DOMCTL_MONITOR_OP_DISABLE )
+        return -EFAULT;
+
+    switch ( domctl->subop )
+    {
+    case XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR0:
+    {
+        /* Note: could be supported on PV domains. */
+        struct mov_to_cr *options = &d->arch.monitor_options.mov_to_cr0;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            options->sync = domctl->u.mov_to_cr.sync;
+            options->onchangeonly = domctl->u.mov_to_cr.onchangeonly;
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR3:
+    {
+        /* Note: could be supported on PV domains. */
+        struct vcpu *v;
+        struct mov_to_cr *options = &d->arch.monitor_options.mov_to_cr3;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            options->sync = domctl->u.mov_to_cr.sync;
+            options->onchangeonly = domctl->u.mov_to_cr.onchangeonly;
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+
+        /* Latches new CR3 mask through CR0 code */
+        for_each_vcpu ( d, v )
+            hvm_funcs.update_guest_cr(v, 0);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR4:
+    {
+        /* Note: could be supported on PV domains. */
+        struct mov_to_cr *options = &d->arch.monitor_options.mov_to_cr4;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            options->sync = domctl->u.mov_to_cr.sync;
+            options->onchangeonly = domctl->u.mov_to_cr.onchangeonly;
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+        break;
+    }
+    case XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_MSR:
+    {
+        struct mov_to_msr *options = &d->arch.monitor_options.mov_to_msr;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            if ( domctl->u.mov_to_msr.extended_capture )
+            {
+                if ( hvm_funcs.enable_msr_exit_interception )
+                {
+                    options->extended_capture = 1;
+                    hvm_funcs.enable_msr_exit_interception(d);
+                }
+                else
+                {
+                    return -ENOSYS;
+                }
+            }
+
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+
+        break;
+    }
+    case XEN_DOMCTL_MONITOR_SUBOP_SINGLESTEP:
+    {
+        struct debug_event *options = &d->arch.monitor_options.singlestep;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+
+        break;
+    }
+    case XEN_DOMCTL_MONITOR_SUBOP_SOFTWARE_BREAKPOINT:
+    {
+        struct debug_event *options =
+            &d->arch.monitor_options.software_breakpoint;
+
+        if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE )
+        {
+            if ( options->enabled )
+                return -EBUSY;
+
+            ENABLE_OPTION(options);
+        }
+        else
+        {
+            DISABLE_OPTION(options);
+        }
+
+        break;
+    }
+
+    default:
+        return -ENOSYS;
+
+    };
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 85afd68..d06f4b6 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -29,6 +29,7 @@
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/p2m.h>
+#include <asm/monitor.h>
 #include <public/domctl.h>
 #include <xsm/xsm.h>
 
@@ -1178,6 +1179,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
     }
     break;
 
+    case XEN_DOMCTL_monitor_op:
+        ret = -EPERM;
+        if ( current->domain == d )
+            break;
+
+        ret = monitor_domctl(&op->u.monitor_op, d);
+        break;
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 57ef58c..5fdac37 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -619,28 +619,17 @@ int vm_event_domctl(struct domain *d, 
xen_domctl_vm_event_op_t *vec,
         switch( vec->op )
         {
         case XEN_VM_EVENT_MONITOR_ENABLE:
-        case XEN_VM_EVENT_MONITOR_ENABLE_INTROSPECTION:
-        {
             rc = vm_event_enable(d, vec, ved, _VPF_mem_access,
-                                    HVM_PARAM_MONITOR_RING_PFN,
-                                    mem_access_notification);
-
-            if ( vec->op == XEN_VM_EVENT_MONITOR_ENABLE_INTROSPECTION
-                 && !rc )
-                p2m_setup_introspection(d);
-
-        }
-        break;
+                                 HVM_PARAM_MONITOR_RING_PFN,
+                                 mem_access_notification);
+            break;
 
         case XEN_VM_EVENT_MONITOR_DISABLE:
-        {
             if ( ved->ring_page )
             {
                 rc = vm_event_disable(d, ved);
-                d->arch.hvm_domain.introspection_enabled = 0;
             }
-        }
-        break;
+            break;
 
         default:
             rc = -ENOSYS;
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
new file mode 100644
index 0000000..ef8f38a
--- /dev/null
+++ b/xen/include/asm-arm/monitor.h
@@ -0,0 +1,13 @@
+#ifndef __ASM_ARM_MONITOR_H__
+#define __ASM_ARM_MONITOR_H__
+
+#include <xen/config.h>
+#include <public/domctl.h>
+
+static inline
+int monitor_domctl(struct xen_domctl_monitor_op *op, struct domain *d)
+{
+    return -ENOSYS;
+}
+
+#endif /* __ASM_X86_MONITOR_H__ */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index e0c4b64..8797f96 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -237,6 +237,24 @@ struct time_scale {
     u32 mul_frac;
 };
 
+/************************************************/
+/*            monitor event options             */
+/************************************************/
+struct mov_to_cr {
+    uint8_t enabled;
+    uint8_t sync;
+    uint8_t onchangeonly;
+};
+
+struct mov_to_msr {
+    uint8_t enabled;
+    uint8_t extended_capture;
+};
+
+struct debug_event {
+    uint8_t enabled;
+};
+
 struct pv_domain
 {
     l1_pgentry_t **gdt_ldt_l1tab;
@@ -331,6 +349,16 @@ struct arch_domain
     unsigned long pirq_eoi_map_mfn;
 
     unsigned int psr_rmid; /* RMID assigned to the domain for CMT */
+
+    /* Monitor options */
+    struct {
+        struct mov_to_cr mov_to_cr0;
+        struct mov_to_cr mov_to_cr3;
+        struct mov_to_cr mov_to_cr4;
+        struct mov_to_msr mov_to_msr;
+        struct debug_event singlestep;
+        struct debug_event software_breakpoint;
+    } monitor_options;
 } __cacheline_aligned;
 
 #define has_arch_pdevs(d)    (!list_empty(&(d)->arch.pdev_list))
diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
index 2757c7f..0f8b19a 100644
--- a/xen/include/asm-x86/hvm/domain.h
+++ b/xen/include/asm-x86/hvm/domain.h
@@ -134,7 +134,6 @@ struct hvm_domain {
     bool_t                 mem_sharing_enabled;
     bool_t                 qemu_mapcache_invalidate;
     bool_t                 is_s3_suspended;
-    bool_t                 introspection_enabled;
 
     /*
      * TSC value that VCPUs use to calculate their tsc_offset value.
diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h
new file mode 100644
index 0000000..91204b8
--- /dev/null
+++ b/xen/include/asm-x86/monitor.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_X86_MONITOR_H__
+#define __ASM_X86_MONITOR_H__
+
+#include <public/domctl.h>
+
+int monitor_domctl(struct xen_domctl_monitor_op *op, struct domain *d);
+
+#endif /* __ASM_X86_MONITOR_H__ */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index ef373eb..c82a992 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -803,7 +803,6 @@ struct xen_domctl_gdbsx_domstatus {
 
 #define XEN_VM_EVENT_MONITOR_ENABLE                           0
 #define XEN_VM_EVENT_MONITOR_DISABLE                          1
-#define XEN_VM_EVENT_MONITOR_ENABLE_INTROSPECTION             2
 
 /*
  * Sharing ENOMEM helper.
@@ -1001,6 +1000,53 @@ struct xen_domctl_psr_cmt_op {
 typedef struct xen_domctl_psr_cmt_op xen_domctl_psr_cmt_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 
+/*  XEN_DOMCTL_MONITOR_*
+ *
+ * Enable/disable monitoring various VM events.
+ * This domctl configures what events will be reported to helper apps
+ * via the ring buffer "MONITOR". The ring has to be first enabled
+ * with the domctl XEN_DOMCTL_VM_EVENT_OP_MONITOR.
+ *
+ * NOTICE: mem_access events are also delivered via the "MONITOR" ring buffer;
+ * however, enabling/disabling those events is performed with the use of
+ * memory_op hypercalls!
+ */
+#define XEN_DOMCTL_MONITOR_OP_ENABLE   0
+#define XEN_DOMCTL_MONITOR_OP_DISABLE  1
+
+#define XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR0            0
+#define XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR3            1
+#define XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_CR4            2
+#define XEN_DOMCTL_MONITOR_SUBOP_MOV_TO_MSR            3
+#define XEN_DOMCTL_MONITOR_SUBOP_SINGLESTEP            4
+#define XEN_DOMCTL_MONITOR_SUBOP_SOFTWARE_BREAKPOINT   5
+
+struct xen_domctl_monitor_op {
+    uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
+    uint32_t subop; /* XEN_DOMCTL_MONITOR_SUBOP_* */
+
+    /*
+     * Further options when issuing XEN_DOMCTL_MONITOR_OP_ENABLE.
+     */
+    union {
+        struct {
+            /* Pause vCPU until response */
+            uint8_t sync;
+            /* Send event only on a change of value */
+            uint8_t onchangeonly;
+            uint8_t _pad[6];
+        } mov_to_cr;
+
+        struct {
+            /* Enable the capture of an extended set of MSRs */
+            uint8_t extended_capture;
+            uint8_t _pad[7];
+        } mov_to_msr;
+    } u;
+};
+typedef struct xen_domctl__op xen_domctl_monitor_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_monitor_op_t);
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -1076,6 +1122,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_setvnumainfo                  74
 #define XEN_DOMCTL_psr_cmt_op                    75
 #define XEN_DOMCTL_arm_configure_domain          76
+#define XEN_DOMCTL_monitor_op                    77
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1141,6 +1188,7 @@ struct xen_domctl {
         struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
         struct xen_domctl_vnuma             vnuma;
         struct xen_domctl_psr_cmt_op        psr_cmt_op;
+        struct xen_domctl_monitor_op        monitor_op;
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index 6efcc0b..5de6a4b 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -162,21 +162,6 @@
  */
 #define HVM_PARAM_ACPI_IOPORTS_LOCATION 19
 
-/* Enable blocking memory events, async or sync (pause vcpu until response) 
- * onchangeonly indicates messages only on a change of value */
-#define HVM_PARAM_MEMORY_EVENT_CR0          20
-#define HVM_PARAM_MEMORY_EVENT_CR3          21
-#define HVM_PARAM_MEMORY_EVENT_CR4          22
-#define HVM_PARAM_MEMORY_EVENT_INT3         23
-#define HVM_PARAM_MEMORY_EVENT_SINGLE_STEP  25
-#define HVM_PARAM_MEMORY_EVENT_MSR          30
-
-#define HVMPME_MODE_MASK       (3 << 0)
-#define HVMPME_mode_disabled   0
-#define HVMPME_mode_async      1
-#define HVMPME_mode_sync       2
-#define HVMPME_onchangeonly    (1 << 2)
-
 /* Boolean: Enable nestedhvm (hvm only) */
 #define HVM_PARAM_NESTEDHVM    24
 
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 5667adf..96d599d 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -67,7 +67,7 @@
 #define VM_EVENT_REASON_MOV_TO_CR3              5
 /* CR4 was updated */
 #define VM_EVENT_REASON_MOV_TO_CR4              6
-/* An MSR was updated. Does NOT honour HVMPME_onchangeonly */
+/* An MSR was updated. */
 #define VM_EVENT_REASON_MOV_TO_MSR              7
 /* Debug operation executed (int3) */
 #define VM_EVENT_REASON_SOFTWARE_BREAKPOINT     8
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index c419543..266915f 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -691,6 +691,9 @@ static int flask_domctl(struct domain *d, int cmd)
     case XEN_DOMCTL_set_access_required:
         return current_has_perm(d, SECCLASS_HVM, HVM__VM_EVENT);
 
+    case XEN_DOMCTL_monitor_op:
+        return current_has_perm(d, SECCLASS_HVM, HVM__VM_EVENT);
+
     case XEN_DOMCTL_debug_op:
     case XEN_DOMCTL_gdbsx_guestmemio:
     case XEN_DOMCTL_gdbsx_pausevcpu:
diff --git a/xen/xsm/flask/policy/access_vectors 
b/xen/xsm/flask/policy/access_vectors
index 9da3275..35d1c7b 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -249,6 +249,8 @@ class hvm
 # HVMOP_inject_trap
     hvmctl
 # XEN_DOMCTL_set_access_required
+# XEN_DOMCLT_monitor_op
+# XEN_DOMCLT_vm_event_op
     vm_event
 # XEN_DOMCTL_mem_sharing_op and XENMEM_sharing_op_{share,add_physmap} with:
 #  source = the domain making the hypercall
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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