xen: Introduce monitor_op domctl
authorTamas K Lengyel <tamas.lengyel@zentific.com>
Thu, 9 Apr 2015 14:32:48 +0000 (16:32 +0200)
committerTim Deegan <tim@xen.org>
Thu, 16 Apr 2015 08:41:29 +0000 (09:41 +0100)
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@citrix.com>
Signed-off-by: Tamas K Lengyel <tamas.lengyel@zentific.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Acked-by: Tim Deegan <tim@xen.org>
32 files changed:
MAINTAINERS
tools/libxc/Makefile
tools/libxc/include/xenctrl.h
tools/libxc/xc_domain.c
tools/libxc/xc_mem_access.c
tools/libxc/xc_monitor.c [new file with mode: 0644]
tools/libxc/xc_private.h
tools/libxc/xc_vm_event.c
tools/tests/xen-access/xen-access.c
xen/arch/x86/Makefile
xen/arch/x86/hvm/emulate.c
xen/arch/x86/hvm/event.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/mm/p2m.c
xen/arch/x86/monitor.c [new file with mode: 0644]
xen/common/domctl.c
xen/common/mem_access.c
xen/common/vm_event.c
xen/include/asm-arm/monitor.h [new file with mode: 0644]
xen/include/asm-arm/p2m.h
xen/include/asm-x86/domain.h
xen/include/asm-x86/hvm/domain.h
xen/include/asm-x86/monitor.h [new file with mode: 0644]
xen/include/asm-x86/p2m.h
xen/include/public/domctl.h
xen/include/public/hvm/params.h
xen/include/public/memory.h
xen/include/public/vm_event.h
xen/xsm/flask/hooks.c
xen/xsm/flask/policy/access_vectors

index b7441667007ae3687b9238264952c2523cd1edaf..c714bc102c9d944f1721197ae4428bee7990e2db 100644 (file)
@@ -381,6 +381,7 @@ S:  Supported
 F:     xen/common/vm_event.c
 F:     xen/common/mem_access.c
 F:     xen/arch/x86/hvm/event.c
+F:     xen/arch/x86/monitor.c
 
 XENTRACE
 M:     George Dunlap <george.dunlap@eu.citrix.com>
index 22ba2a19aea22cc8e79b7e4b81cfd58ccd919684..8b609cf182b4daf7a7825b8add630a7ea8095424 100644 (file)
@@ -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
index 02d0db884f1a26d12caefa00e3313630f5be35ed..a1861cbe8c2fee27e6dcdb9c8e45dd428486b3a8 100644 (file)
@@ -34,6 +34,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <xen/xen.h>
 #include <xen/domctl.h>
 #include <xen/physdev.h>
@@ -2311,6 +2312,32 @@ int xc_set_mem_access(xc_interface *xch, domid_t domain_id,
 int xc_get_mem_access(xc_interface *xch, domid_t domain_id,
                       uint64_t pfn, xenmem_access_t *access);
 
+/*
+ * Instructions causing a mem_access violation can be emulated by Xen
+ * to progress the execution without having to relax the mem_access
+ * permissions.
+ * This feature has to be first enabled, then in the vm_event
+ * response to a mem_access event it can be indicated if the instruction
+ * should be emulated.
+ */
+int xc_mem_access_enable_emulate(xc_interface *xch, domid_t domain_id);
+int xc_mem_access_disable_emulate(xc_interface *xch, domid_t domain_id);
+
+/***
+ * Monitor control operations.
+ */
+int xc_monitor_mov_to_cr0(xc_interface *xch, domid_t domain_id, bool enable,
+                          bool sync, bool onchangeonly);
+int xc_monitor_mov_to_cr3(xc_interface *xch, domid_t domain_id, bool enable,
+                          bool sync, bool onchangeonly);
+int xc_monitor_mov_to_cr4(xc_interface *xch, domid_t domain_id, bool enable,
+                          bool sync, bool onchangeonly);
+int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, bool enable,
+                          bool extended_capture);
+int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id, bool enable);
+int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
+                                   bool enable);
+
 /***
  * Memory sharing operations.
  *
index 95e3098e2e9e72102f6557e2f769464d07ee5ee0..7cb36d9481143e8c254041cc2794e41dea57600d 100644 (file)
@@ -1316,11 +1316,32 @@ int xc_domain_send_trigger(xc_interface *xch,
     return do_domctl(xch, &domctl);
 }
 
+static inline int xc_hvm_param_deprecated_check(uint32_t param)
+{
+    switch ( param )
+    {
+        case HVM_PARAM_MEMORY_EVENT_CR0:
+        case HVM_PARAM_MEMORY_EVENT_CR3:
+        case HVM_PARAM_MEMORY_EVENT_CR4:
+        case HVM_PARAM_MEMORY_EVENT_INT3:
+        case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
+        case HVM_PARAM_MEMORY_EVENT_MSR:
+            return -EOPNOTSUPP;
+        default:
+            break;
+    };
+
+    return 0;
+}
+
 int xc_hvm_param_set(xc_interface *handle, domid_t dom, uint32_t param, uint64_t value)
 {
     DECLARE_HYPERCALL;
     DECLARE_HYPERCALL_BUFFER(xen_hvm_param_t, arg);
-    int rc;
+    int rc = xc_hvm_param_deprecated_check(param);
+
+    if ( rc )
+        return rc;
 
     arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
     if ( arg == NULL )
@@ -1341,7 +1362,10 @@ int xc_hvm_param_get(xc_interface *handle, domid_t dom, uint32_t param, uint64_t
 {
     DECLARE_HYPERCALL;
     DECLARE_HYPERCALL_BUFFER(xen_hvm_param_t, arg);
-    int rc;
+    int rc = xc_hvm_param_deprecated_check(param);
+
+    if ( rc )
+        return rc;
 
     arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
     if ( arg == NULL )
index 0a3f0e690c1e4d01d508426ce68544458f9be064..f27bc445c6e119ebd9283a4b936a2f1ea2328f43 100644 (file)
 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)
@@ -95,6 +88,30 @@ int xc_get_mem_access(xc_interface *xch,
     return rc;
 }
 
+int xc_mem_access_enable_emulate(xc_interface *xch,
+                                 domid_t domain_id)
+{
+    xen_mem_access_op_t mao =
+    {
+        .op     = XENMEM_access_op_enable_emulate,
+        .domid  = domain_id,
+    };
+
+    return do_memory_op(xch, XENMEM_access_op, &mao, sizeof(mao));
+}
+
+int xc_mem_access_disable_emulate(xc_interface *xch,
+                                  domid_t domain_id)
+{
+    xen_mem_access_op_t mao =
+    {
+        .op     = XENMEM_access_op_disable_emulate,
+        .domid  = domain_id,
+    };
+
+    return do_memory_op(xch, XENMEM_access_op, &mao, sizeof(mao));
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
new file mode 100644 (file)
index 0000000..fe090bc
--- /dev/null
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * xc_monitor.c
+ *
+ * Interface to VM event monitor
+ *
+ * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
+ *
+ * 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, bool enable,
+                          bool sync, bool onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_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, bool enable,
+                          bool sync, bool onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_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, bool enable,
+                          bool sync, bool onchangeonly)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_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, bool enable,
+                          bool extended_capture)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_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,
+                                   bool enable)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT;
+
+    return do_domctl(xch, &domctl);
+}
+
+int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id,
+                          bool enable)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP;
+
+    return do_domctl(xch, &domctl);
+}
index 843540c79ef3aa197663465e000cca382f0199af..9f553096cde27b7c1eca4876ab55eb17e1e79b05 100644 (file)
@@ -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__ */
index d458b9a67a910267c1292293eeea1be94be2e59d..7277e86d47719379ff2f83d25aa5dbd784c0d6b6 100644 (file)
@@ -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;
 
index d667bf5abaaf13f76bcd3404f37cf102887f957f..23438fcfb32a586bfef26deb312224d843fc6df1 100644 (file)
@@ -317,9 +317,9 @@ static void put_response(vm_event_t *vm_event, vm_event_response_t *rsp)
 void usage(char* progname)
 {
     fprintf(stderr,
-            "Usage: %s [-m] <domain_id> write|exec|int3\n"
+            "Usage: %s [-m] <domain_id> write|exec|breakpoint\n"
             "\n"
-            "Logs first page writes, execs, or int3 traps that occur on the domain.\n"
+            "Logs first page writes, execs, or breakpoint traps that occur on the domain.\n"
             "\n"
             "-m requires this program to run, or else the domain may pause\n",
             progname);
@@ -338,7 +338,7 @@ int main(int argc, char *argv[])
     xenmem_access_t default_access = XENMEM_access_rwx;
     xenmem_access_t after_first_access = XENMEM_access_rwx;
     int required = 0;
-    int int3 = 0;
+    int breakpoint = 0;
     int shutting_down = 0;
 
     char* progname = argv[0];
@@ -378,9 +378,9 @@ int main(int argc, char *argv[])
         default_access = XENMEM_access_rw;
         after_first_access = XENMEM_access_rwx;
     }
-    else if ( !strcmp(argv[0], "int3") )
+    else if ( !strcmp(argv[0], "breakpoint") )
     {
-        int3 = 1;
+        breakpoint = 1;
     }
     else
     {
@@ -431,14 +431,14 @@ int main(int argc, char *argv[])
         goto exit;
     }
 
-    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 )
+    if ( breakpoint )
     {
-        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 breakpoint trapping with vm_event\n", rc);
+            goto exit;
+        }
     }
 
     /* Wait for access */
@@ -452,7 +452,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;
         }
@@ -527,7 +527,7 @@ int main(int argc, char *argv[])
                 rsp.u.mem_access.gfn = req.u.mem_access.gfn;
                 break;
             case VM_EVENT_REASON_SOFTWARE_BREAKPOINT:
-                printf("INT3: rip=%016"PRIx64", gfn=%"PRIx64" (vcpu %d)\n",
+                printf("Breakpoint: rip=%016"PRIx64", gfn=%"PRIx64" (vcpu %d)\n",
                        req.regs.x86.rip,
                        req.u.software_breakpoint.gfn,
                        req.vcpu_id);
@@ -538,7 +538,7 @@ int main(int argc, char *argv[])
                     HVMOP_TRAP_sw_exc, -1, 0, 0);
                 if (rc < 0)
                 {
-                    ERROR("Error %d injecting int3\n", rc);
+                    ERROR("Error %d injecting breakpoint\n", rc);
                     interrupted = -1;
                     continue;
                 }
index 86ca5f8f755a1b3ecb5b7436f39f17bc7916c3d0..37e547cfeecf09fa3edff9c08e6fcc5c7b39782c 100644 (file)
@@ -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
index 40de77690038595b1d31326f3bb7430bad015646..ac9c9d6fc577658d66bbc02aaa59c004732916e8 100644 (file)
@@ -418,7 +418,7 @@ 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.mem_access_emulate_enabled)
                            ? 1 : 4096);
 
     reg = hvmemul_get_seg_reg(seg, hvmemul_ctxt);
index dfb0ab7fa7c6c7f8f3c06d762ccafe4372cc2cc6..9d5f9f357228ff838235bb2ba7a3838d957418d7 100644 (file)
@@ -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(uint64_t 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(uint64_t 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);
@@ -91,41 +88,53 @@ static int hvm_event_traps(uint64_t parameters, vm_event_request_t *req)
     return 1;
 }
 
-static void hvm_event_cr(uint32_t reason, unsigned long value,
-                         unsigned long old, uint64_t parameters)
+static inline
+void hvm_event_cr(uint32_t reason, unsigned long value,
+                         unsigned long old, bool_t onchangeonly, bool_t sync)
 {
-    vm_event_request_t req = {
-        .reason = reason,
-        .vcpu_id = current->vcpu_id,
-        .u.mov_to_cr.new_value = value,
-        .u.mov_to_cr.old_value = old
-    };
-
-    if ( (parameters & HVMPME_onchangeonly) && (value == old) )
+    if ( onchangeonly && value == old )
         return;
-
-    hvm_event_traps(parameters, &req);
+    else
+    {
+        vm_event_request_t req = {
+            .reason = reason,
+            .vcpu_id = current->vcpu_id,
+            .u.mov_to_cr.new_value = value,
+            .u.mov_to_cr.old_value = old
+        };
+
+        hvm_event_traps(sync, &req);
+    }
 }
 
 void hvm_event_cr0(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR0, value, old,
-                 current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR0]);
+    struct arch_domain *currad = &current->domain->arch;
+
+    if ( currad->monitor.mov_to_cr0_enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR0, value, old,
+                     currad->monitor.mov_to_cr0_onchangeonly,
+                     currad->monitor.mov_to_cr0_sync);
 }
 
 void hvm_event_cr3(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR3, value, old,
-                 current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR3]);
+    struct arch_domain *currad = &current->domain->arch;
+
+    if ( currad->monitor.mov_to_cr3_enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR3, value, old,
+                     currad->monitor.mov_to_cr3_onchangeonly,
+                     currad->monitor.mov_to_cr3_sync);
 }
 
 void hvm_event_cr4(unsigned long value, unsigned long old)
 {
-    hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR4, value, old,
-                 current->domain->arch.hvm_domain
-                      .params[HVM_PARAM_MEMORY_EVENT_CR4]);
+    struct arch_domain *currad = &current->domain->arch;
+
+    if ( currad->monitor.mov_to_cr4_enabled )
+        hvm_event_cr(VM_EVENT_REASON_MOV_TO_CR4, value, old,
+                     currad->monitor.mov_to_cr4_onchangeonly,
+                     currad->monitor.mov_to_cr4_sync);
 }
 
 void hvm_event_msr(unsigned int msr, uint64_t value)
@@ -137,14 +146,14 @@ void hvm_event_msr(unsigned int msr, uint64_t value)
         .u.mov_to_msr.msr = msr,
         .u.mov_to_msr.value = value,
     };
-    uint64_t params = curr->domain->arch.hvm_domain
-                        .params[HVM_PARAM_MEMORY_EVENT_MSR];
 
-    hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor.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 = {
@@ -152,14 +161,16 @@ int hvm_event_int3(unsigned long gla)
         .vcpu_id = curr->vcpu_id,
         .u.software_breakpoint.gfn = paging_gva_to_gfn(curr, gla, &pfec)
     };
-    uint64_t params = curr->domain->arch.hvm_domain
-                        .params[HVM_PARAM_MEMORY_EVENT_INT3];
 
-    return hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor.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 = {
@@ -167,10 +178,11 @@ int hvm_event_single_step(unsigned long gla)
         .vcpu_id = curr->vcpu_id,
         .u.singlestep.gfn = paging_gva_to_gfn(curr, gla, &pfec)
     };
-    uint64_t params = curr->domain->arch.hvm_domain
-                        .params[HVM_PARAM_MEMORY_EVENT_SINGLE_STEP];
 
-    return hvm_event_traps(params, &req);
+    if ( curr->domain->arch.monitor.singlestep_enabled )
+        rc = hvm_event_traps(1, &req);
+
+    return rc;
 }
 
 /*
index 9dfaa287e81ea816c491a61aa7ace2b3bd327a3c..21cf744ea9919e1b1000f0ebf6da7fe973e7ac5f 100644 (file)
@@ -5807,19 +5807,11 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
             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;
+                /* Deprecated */
+                rc = -EOPNOTSUPP;
                 break;
             case HVM_PARAM_NESTEDHVM:
                 rc = xsm_hvm_param_nested(XSM_PRIV, d);
@@ -5879,29 +5871,8 @@ 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
         {
index 63007a99545f08a6a9eea00f70c6b7f7be77decc..8b98a9f52ec771235bcee8439b49e5e57e409033 100644 (file)
@@ -714,7 +714,8 @@ 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.mov_to_msr_enabled &&
+                  d->arch.monitor.mov_to_msr_extended) &&
          vm_event_check_ring(&d->vm_event->monitor) )
     {
         unsigned int i;
@@ -1373,8 +1374,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.software_breakpoint_enabled
+                  || v->domain->arch.monitor.singlestep_enabled;
 
     if ( unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
index 04b681daf8f8cd6ddbc50add9322e16fcc12ce1d..211eafc88706db3c227fc4588f7ab0f528ebbf7b 100644 (file)
@@ -1231,7 +1231,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.mov_to_cr3_enabled )
                 v->arch.hvm_vmx.exec_control |= CPU_BASED_CR3_LOAD_EXITING;
 
             vmx_update_cpu_exec_control(v);
index df4a48556a3635c076b2fe5cb9fabb8546f0ec9c..1d3356adb6dbe7fb7c509d7cdd4a5a5a3941ef1f 100644 (file)
@@ -1454,15 +1454,6 @@ void p2m_mem_access_emulate_check(struct vcpu *v,
     }
 }
 
-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 (file)
index 0000000..d7b1c18
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * arch/x86/monitor.c
+ *
+ * Architecture-specific monitor_op domctl handler.
+ *
+ * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
+ *
+ * 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>
+#include <asm/monitor.h>
+#include <public/domctl.h>
+#include <xsm/xsm.h>
+
+/*
+ * Sanity check whether option is already enabled/disabled
+ */
+static inline
+int status_check(struct xen_domctl_monitor_op *mop, bool_t status)
+{
+    bool_t requested_status = (mop->op == XEN_DOMCTL_MONITOR_OP_ENABLE);
+
+    if ( status == requested_status )
+        return -EEXIST;
+
+    return 0;
+}
+
+int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
+{
+    int rc;
+    struct arch_domain *ad = &d->arch;
+
+    rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event);
+    if ( rc )
+        return rc;
+
+    /*
+     * At the moment only Intel HVM domains are supported. However, event
+     * delivery could be extended to AMD and PV domains.
+     */
+    if ( !is_hvm_domain(d) || !cpu_has_vmx )
+        return -EOPNOTSUPP;
+
+    /*
+     * Sanity check
+     */
+    if ( mop->op != XEN_DOMCTL_MONITOR_OP_ENABLE &&
+         mop->op != XEN_DOMCTL_MONITOR_OP_DISABLE )
+        return -EOPNOTSUPP;
+
+    switch ( mop->event )
+    {
+    case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_CR0:
+    {
+        bool_t status = ad->monitor.mov_to_cr0_enabled;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        ad->monitor.mov_to_cr0_sync = mop->u.mov_to_cr.sync;
+        ad->monitor.mov_to_cr0_onchangeonly = mop->u.mov_to_cr.onchangeonly;
+
+        domain_pause(d);
+        ad->monitor.mov_to_cr0_enabled = !status;
+        domain_unpause(d);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_CR3:
+    {
+        bool_t status = ad->monitor.mov_to_cr3_enabled;
+        struct vcpu *v;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        ad->monitor.mov_to_cr3_sync = mop->u.mov_to_cr.sync;
+        ad->monitor.mov_to_cr3_onchangeonly = mop->u.mov_to_cr.onchangeonly;
+
+        domain_pause(d);
+        ad->monitor.mov_to_cr3_enabled = !status;
+        domain_unpause(d);
+
+        /* Latches new CR3 mask through CR0 code */
+        for_each_vcpu ( d, v )
+            hvm_funcs.update_guest_cr(v, 0);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_CR4:
+    {
+        bool_t status = ad->monitor.mov_to_cr4_enabled;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        ad->monitor.mov_to_cr4_sync = mop->u.mov_to_cr.sync;
+        ad->monitor.mov_to_cr4_onchangeonly = mop->u.mov_to_cr.onchangeonly;
+
+        domain_pause(d);
+        ad->monitor.mov_to_cr4_enabled = !status;
+        domain_unpause(d);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR:
+    {
+        bool_t status = ad->monitor.mov_to_msr_enabled;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        if ( mop->op == XEN_DOMCTL_MONITOR_OP_ENABLE &&
+             mop->u.mov_to_msr.extended_capture )
+        {
+            if ( hvm_funcs.enable_msr_exit_interception )
+            {
+                ad->monitor.mov_to_msr_extended = 1;
+                hvm_funcs.enable_msr_exit_interception(d);
+            }
+            else
+                return -EOPNOTSUPP;
+        } else
+            ad->monitor.mov_to_msr_extended = 0;
+
+        domain_pause(d);
+        ad->monitor.mov_to_msr_enabled = !status;
+        domain_unpause(d);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP:
+    {
+        bool_t status = ad->monitor.singlestep_enabled;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        domain_pause(d);
+        ad->monitor.singlestep_enabled = !status;
+        domain_unpause(d);
+        break;
+    }
+
+    case XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT:
+    {
+        bool_t status = ad->monitor.software_breakpoint_enabled;
+
+        rc = status_check(mop, status);
+        if ( rc )
+            return rc;
+
+        domain_pause(d);
+        ad->monitor.software_breakpoint_enabled = !status;
+        domain_unpause(d);
+        break;
+    }
+
+    default:
+        return -EOPNOTSUPP;
+
+    };
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index b722143811bc9e8efb43235bc527a47c58a3c13d..28aea55f44bc208814409e88b8ad39920ca1ad17 100644 (file)
@@ -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>
 
@@ -1159,6 +1160,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(d, &op->u.monitor_op);
+        break;
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
index 4bbe2f9765ce8dd98e6bd4a26d8edf981acc629e..f925ac7be5faa2c4126be1517ce70251bcdd4a29 100644 (file)
@@ -140,6 +140,14 @@ int mem_access_memop(unsigned long cmd,
         break;
     }
 
+    case XENMEM_access_op_enable_emulate:
+        rc = p2m_mem_access_enable_emulate(d);
+        break;
+
+    case XENMEM_access_op_disable_emulate:
+        rc = p2m_mem_access_disable_emulate(d);
+        break;
+
     default:
         rc = -ENOSYS;
         break;
index 9afb54fd07a014b45e618829d2396aff711648bd..7c532fcef2700bed7adf6058a55fba4fcc67fe7b 100644 (file)
@@ -599,11 +599,9 @@ int vm_event_domctl(struct domain *d, xen_domctl_vm_event_op_t *vec,
         break;
 
         case XEN_VM_EVENT_PAGING_DISABLE:
-        {
             if ( ved->ring_page )
                 rc = vm_event_disable(d, ved);
-        }
-        break;
+            break;
 
         default:
             rc = -ENOSYS;
@@ -622,32 +620,15 @@ 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 = -ENODEV;
-            if ( !p2m_vm_event_sanity_check(d) )
-                break;
-
             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;
+            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;
@@ -666,7 +647,6 @@ int vm_event_domctl(struct domain *d, xen_domctl_vm_event_op_t *vec,
         switch( vec->op )
         {
         case XEN_VM_EVENT_SHARING_ENABLE:
-        {
             rc = -EOPNOTSUPP;
             /* pvh fixme: p2m_is_foreign types need addressing */
             if ( is_pvh_vcpu(current) || is_pvh_domain(hardware_domain) )
@@ -680,15 +660,12 @@ int vm_event_domctl(struct domain *d, xen_domctl_vm_event_op_t *vec,
             rc = vm_event_enable(d, vec, ved, _VPF_mem_sharing,
                                  HVM_PARAM_SHARING_RING_PFN,
                                  mem_sharing_notification);
-        }
-        break;
+            break;
 
         case XEN_VM_EVENT_SHARING_DISABLE:
-        {
             if ( ved->ring_page )
                 rc = vm_event_disable(d, ved);
-        }
-        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 (file)
index 0000000..0f01e06
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * include/asm-arm/monitor.h
+ *
+ * Architecture-specific monitor_op domctl handler.
+ *
+ * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARM_MONITOR_H__
+#define __ASM_ARM_MONITOR_H__
+
+#include <xen/sched.h>
+#include <public/domctl.h>
+
+static inline
+int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op)
+{
+    return -ENOSYS;
+}
+
+#endif /* __ASM_X86_MONITOR_H__ */
index 23cf7d82cb4a2bc1826626c1c324004cf8f45e5f..11efb5b4c63b02ac1ee3864d3a6eb84082d85b17 100644 (file)
@@ -71,16 +71,24 @@ typedef enum {
 } p2m_type_t;
 
 static inline
-void p2m_mem_access_emulate_check(struct vcpu *v,
-                                  const vm_event_response_t *rsp)
+int p2m_mem_access_enable_emulate(struct domain *d)
 {
-    /* Not supported on ARM. */
+    /* Not supported on ARM */
+    return -ENOSYS;
+}
+
+static inline
+int p2m_mem_access_disable_emulate(struct domain *d)
+{
+    /* Not supported on ARM */
+    return -ENOSYS;
 }
 
 static inline
-void p2m_setup_introspection(struct domain *d)
+void p2m_mem_access_emulate_check(struct vcpu *v,
+                                  const vm_event_response_t *rsp)
 {
-    /* No special setup on ARM. */
+    /* Not supported on ARM. */
 }
 
 #define p2m_is_foreign(_t)  ((_t) == p2m_map_foreign)
index e5102cca279f442fc46f380db238ccaa61d5bd09..3f83e8ba594296394f160f435d4f98aeca7d9e41 100644 (file)
@@ -338,7 +338,27 @@ struct arch_domain
     /* Shared page for notifying that explicit PIRQ EOI is required. */
     unsigned long *pirq_eoi_map;
     unsigned long pirq_eoi_map_mfn;
-};
+
+    /* Monitor options */
+    struct {
+        uint16_t mov_to_cr0_enabled          : 1;
+        uint16_t mov_to_cr0_sync             : 1;
+        uint16_t mov_to_cr0_onchangeonly     : 1;
+        uint16_t mov_to_cr3_enabled          : 1;
+        uint16_t mov_to_cr3_sync             : 1;
+        uint16_t mov_to_cr3_onchangeonly     : 1;
+        uint16_t mov_to_cr4_enabled          : 1;
+        uint16_t mov_to_cr4_sync             : 1;
+        uint16_t mov_to_cr4_onchangeonly     : 1;
+        uint16_t mov_to_msr_enabled          : 1;
+        uint16_t mov_to_msr_extended         : 1;
+        uint16_t singlestep_enabled          : 1;
+        uint16_t software_breakpoint_enabled : 1;
+    } monitor;
+
+    /* Mem_access emulation control */
+    bool_t mem_access_emulate_enabled;
+} __cacheline_aligned;
 
 #define has_arch_pdevs(d)    (!list_empty(&(d)->arch.pdev_list))
 
index 2757c7fedd4fa8a0c8f7b0d7b0c5f0cc2bc6cbd1..0f8b19af2de84fdae64d3ef9da9ded831cdc9138 100644 (file)
@@ -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 (file)
index 0000000..21b3e5b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * include/asm-x86/monitor.h
+ *
+ * Architecture-specific monitor_op domctl handler.
+ *
+ * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
+ *
+ * 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.
+ */
+
+#ifndef __ASM_X86_MONITOR_H__
+#define __ASM_X86_MONITOR_H__
+
+struct domain;
+struct xen_domctl_monitor_op;
+
+int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op);
+
+#endif /* __ASM_X86_MONITOR_H__ */
index 91fc099651cf8bddce012739dcf39f2497bdcdc5..2b5f0fcdc8948d81b6a06c2a67b069598722cf25 100644 (file)
@@ -607,24 +607,39 @@ long p2m_set_mem_access(struct domain *d, unsigned long start_pfn, uint32_t nr,
 int p2m_get_mem_access(struct domain *d, unsigned long pfn,
                        xenmem_access_t *access);
 
-/* Check for emulation and mark vcpu for skipping one instruction
- * upon rescheduling if required. */
-void p2m_mem_access_emulate_check(struct vcpu *v,
-                                  const vm_event_response_t *rsp);
+/*
+ * Emulating a memory access requires custom handling. These non-atomic
+ * functions should be called under domctl lock.
+ */
+static inline
+int p2m_mem_access_enable_emulate(struct domain *d)
+{
+    if ( d->arch.mem_access_emulate_enabled )
+        return -EEXIST;
 
-/* Enable arch specific introspection options (such as MSR interception). */
-void p2m_setup_introspection(struct domain *d);
+    d->arch.mem_access_emulate_enabled = 1;
+    return 0;
+}
 
-/* Sanity check for vm_event hardware support */
-static inline bool_t p2m_vm_event_sanity_check(struct domain *d)
+static inline
+int p2m_mem_access_disable_emulate(struct domain *d)
 {
-    return hap_enabled(d) && cpu_has_vmx;
+    if ( !d->arch.mem_access_emulate_enabled )
+        return -EEXIST;
+
+    d->arch.mem_access_emulate_enabled = 0;
+    return 0;
 }
 
+/* Check for emulation and mark vcpu for skipping one instruction
+ * upon rescheduling if required. */
+void p2m_mem_access_emulate_check(struct vcpu *v,
+                                  const vm_event_response_t *rsp);
+
 /* Sanity check for mem_access hardware support */
 static inline bool_t p2m_mem_access_sanity_check(struct domain *d)
 {
-    return is_hvm_domain(d);
+    return is_hvm_domain(d) && cpu_has_vmx && hap_enabled(d);
 }
 
 /* 
index d2e8db0e46cbf85497faf4c82c0505949277fe62..3e5d1f4a2d92d214467b4cfdb30f24aae9bfffa7 100644 (file)
@@ -793,7 +793,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,51 @@ 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_EVENT_MOV_TO_CR0            0
+#define XEN_DOMCTL_MONITOR_EVENT_MOV_TO_CR3            1
+#define XEN_DOMCTL_MONITOR_EVENT_MOV_TO_CR4            2
+#define XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR            3
+#define XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP            4
+#define XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT   5
+
+struct xen_domctl_monitor_op {
+    uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
+    uint32_t event; /* XEN_DOMCTL_MONITOR_EVENT_* */
+
+    /*
+     * 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;
+        } mov_to_cr;
+
+        struct {
+            /* Enable the capture of an extended set of MSRs */
+            uint8_t extended_capture;
+        } 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
@@ -1075,6 +1119,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_set_vcpu_msrs                 73
 #define XEN_DOMCTL_setvnumainfo                  74
 #define XEN_DOMCTL_psr_cmt_op                    75
+#define XEN_DOMCTL_monitor_op                    77
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1137,6 +1182,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;
 };
index 6efcc0bf59a730b9dd28d4f8cbd44c78aaf75640..7c73089b895e4179e19916e996e5ee6c31af8913 100644 (file)
  */
 #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 */
+/* Deprecated */
 #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_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
 
index 043c26d222b4934e6b260abbd3c33afa012e3d37..1fe3f7520d72fe6f257f7c4e1fe2774ae8310624 100644 (file)
@@ -390,6 +390,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_mem_paging_op_t);
 #define XENMEM_access_op_resume             0
 #define XENMEM_access_op_set_access         1
 #define XENMEM_access_op_get_access         2
+#define XENMEM_access_op_enable_emulate     3
+#define XENMEM_access_op_disable_emulate    4
 
 typedef enum {
     XENMEM_access_n,
index 28d8d7a0926166cec87c199dc2a3eb5baf51b3c0..ed9105bd758f771d086e37d9dab021bf66f5a1f4 100644 (file)
@@ -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 (e.g. int3) */
 #define VM_EVENT_REASON_SOFTWARE_BREAKPOINT     8
index ab5141d610ff9055c8b8f7fb95518e8c01b8f55a..bd712b23c7cc104dfb54be7e4b5259e6209bc0ac 100644 (file)
@@ -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:
index 128250eb13fad3e891916f686060274f9396ecf8..4f392a51eac917f69ff8f48b0cb6efc5bc3acd77 100644 (file)
@@ -248,6 +248,8 @@ class hvm
 # HVMOP_inject_trap
     hvmctl
 # XEN_DOMCTL_set_access_required
+# XEN_DOMCTL_monitor_op
+# XEN_DOMCTL_vm_event_op
     vm_event
 # XEN_DOMCTL_mem_sharing_op and XENMEM_sharing_op_{share,add_physmap} with:
 #  source = the domain making the hypercall