[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH V3 10/12] 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> --- 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/event.c | 41 ++------ xen/arch/x86/hvm/hvm.c | 38 +------ xen/arch/x86/hvm/vmx/vmcs.c | 4 +- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/arch/x86/mm/p2m.c | 9 -- xen/arch/x86/monitor.c | 197 ++++++++++++++++++++++++++++++++++++ xen/common/domctl.c | 11 ++ xen/common/vm_event.c | 7 -- xen/include/asm-arm/monitor.h | 13 +++ xen/include/asm-x86/domain.h | 45 ++++++++ xen/include/asm-x86/monitor.h | 9 ++ xen/include/public/domctl.h | 55 +++++++++- xen/include/public/hvm/params.h | 15 --- xen/include/public/vm_event.h | 2 +- 22 files changed, 495 insertions(+), 124 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 6ef17ec..2d79e7c 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -27,6 +27,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 0ad8b8d..6428365 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 aa6e777..70cc8d0 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..ee5a37b --- /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.options.mov_to_cr0.sync = sync; + domctl.u.monitor_op.options.mov_to_cr0.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.options.mov_to_cr3.sync = sync; + domctl.u.monitor_op.options.mov_to_cr3.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.options.mov_to_cr4.sync = sync; + domctl.u.monitor_op.options.mov_to_cr4.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.options.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 bd14c9d..12d2169 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_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE_INTROSPECTION; - else - op = XEN_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE; + op = XEN_DOMCTL_VM_EVENT_OP_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 c9aaed4..5411eab 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/event.c b/xen/arch/x86/hvm/event.c index 65f80a7..34975b4 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); if ( rc == -ENOSYS ) { @@ -74,7 +71,7 @@ static int hvm_event_traps(long parameters, vm_event_request_t *req) else if ( rc < 0 ) return rc; - if ( (parameters & HVMPME_MODE_MASK) == HVMPME_mode_sync ) + if ( sync ) { req->flags |= VM_EVENT_FLAG_VCPU_PAUSED; vm_event_vcpu_pause(curr); @@ -97,12 +94,10 @@ void hvm_event_cr0(unsigned long value, unsigned long old) .data.mov_to_cr.old_value = old }; - long params = currd->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_CR0]; - - if ( (params & HVMPME_onchangeonly) && (value == old) ) + if ( currd->arch.monitor_options.mov_to_cr0.onchangeonly && value == old ) return; - hvm_event_traps(params, &req); + hvm_event_traps(currd->arch.monitor_options.mov_to_cr0.sync, &req); } void hvm_event_cr3(unsigned long value, unsigned long old) @@ -116,12 +111,10 @@ void hvm_event_cr3(unsigned long value, unsigned long old) .data.mov_to_cr.old_value = old }; - long params = currd->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_CR3]; - - if ( (params & HVMPME_onchangeonly) && (value == old) ) + if ( currd->arch.monitor_options.mov_to_cr3.onchangeonly && value == old ) return; - hvm_event_traps(params, &req); + hvm_event_traps(currd->arch.monitor_options.mov_to_cr3.sync, &req); } void hvm_event_cr4(unsigned long value, unsigned long old) @@ -135,18 +128,15 @@ void hvm_event_cr4(unsigned long value, unsigned long old) .data.mov_to_cr.old_value = old }; - long params = currd->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_CR4]; - - if ( (params & HVMPME_onchangeonly) && (value == old) ) + if ( currd->arch.monitor_options.mov_to_cr4.onchangeonly && value == old ) return; - hvm_event_traps(params, &req); + hvm_event_traps(currd->arch.monitor_options.mov_to_cr3.sync, &req); } void hvm_event_msr(unsigned long msr, unsigned long value) { struct vcpu *curr = current; - struct domain *currd = curr->domain; vm_event_request_t req = { .reason = VM_EVENT_REASON_MOV_TO_MSR, .vcpu_id = curr->vcpu_id, @@ -154,42 +144,33 @@ void hvm_event_msr(unsigned long msr, unsigned long value) .data.mov_to_msr.value = value, }; - long params = currd->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_MSR]; - - hvm_event_traps(params, &req); + hvm_event_traps(1, &req); } int hvm_event_int3(unsigned long gla) { uint32_t pfec = PFEC_page_present; struct vcpu *curr = current; - struct domain *currd = curr->domain; vm_event_request_t req = { .reason = VM_EVENT_REASON_SOFTWARE_BREAKPOINT, .vcpu_id = curr->vcpu_id, .data.software_breakpoint.gfn = paging_gva_to_gfn(curr, gla, &pfec) }; - long params = currd->arch.hvm_domain.params[HVM_PARAM_MEMORY_EVENT_INT3]; - - return hvm_event_traps(params, &req); + return hvm_event_traps(1, &req); } int hvm_event_single_step(unsigned long gla) { uint32_t pfec = PFEC_page_present; struct vcpu *curr = current; - struct domain *currd = curr->domain; vm_event_request_t req = { .reason = VM_EVENT_REASON_SINGLESTEP, .vcpu_id = curr->vcpu_id, .data.singlestep.gfn = paging_gva_to_gfn(curr, gla, &pfec) }; - long params = currd->arch.hvm_domain - .params[HVM_PARAM_MEMORY_EVENT_SINGLE_STEP]; - - return hvm_event_traps(params, &req); + return hvm_event_traps(1, &req); } /* diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 97f769a..0baeee3 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -5727,23 +5727,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 ) @@ -5802,29 +5785,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 0f2b2e6..9787f3f 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -1375,8 +1375,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 c5e6771..ce3dcbd 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 c7a0bde..3b58700 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1445,15 +1445,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..c172aaf --- /dev/null +++ b/xen/arch/x86/monitor.c @@ -0,0 +1,197 @@ +/* + * 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) \ + if ( !option->enabled ) \ + return -EFAULT; \ + memset(option, 0, sizeof(*option)) + +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_cr0 *options = &d->arch.monitor_options.mov_to_cr0; + + if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE ) + { + if ( options->enabled ) + return -EBUSY; + + options->enabled = 1; + options->sync = domctl->options.mov_to_cr0.sync; + options->onchangeonly = domctl->options.mov_to_cr0.onchangeonly; + } + 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_cr3 *options = &d->arch.monitor_options.mov_to_cr3; + + if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE ) + { + if ( options->enabled ) + return -EBUSY; + + options->enabled = 1; + options->sync = domctl->options.mov_to_cr3.sync; + options->onchangeonly = domctl->options.mov_to_cr3.onchangeonly; + } + 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_cr4 *options = &d->arch.monitor_options.mov_to_cr4; + + if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE ) + { + if ( options->enabled ) + return -EBUSY; + + options->enabled = 1; + options->sync = domctl->options.mov_to_cr4.sync; + options->onchangeonly = domctl->options.mov_to_cr4.onchangeonly; + } + 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; + + options->enabled = 1; + + if ( domctl->options.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; + } + } + } + else + { + DISABLE_OPTION(options); + } + + break; + } + case XEN_DOMCTL_MONITOR_SUBOP_SINGLESTEP: + { + struct singlestep *options = &d->arch.monitor_options.singlestep; + + if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE ) + { + if ( options->enabled ) + return -EBUSY; + + options->enabled = 1; + } + else + { + DISABLE_OPTION(options); + } + + /* Causes guest to latch new status */ + domain_pause(d); + domain_unpause(d); + break; + } + case XEN_DOMCTL_MONITOR_SUBOP_SOFTWARE_BREAKPOINT: + { + struct software_breakpoint *options = + &d->arch.monitor_options.software_breakpoint; + + if ( domctl->op == XEN_DOMCTL_MONITOR_OP_ENABLE ) + { + if ( options->enabled ) + return -EBUSY; + + options->enabled = 1; + } + else + { + DISABLE_OPTION(options); + } + + domain_pause(d); + domain_unpause(d); /* Causes guest to latch new status */ + break; + } + + default: + return -EFAULT; + + }; + + 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 44d45d1..98c2dc6 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> @@ -1179,6 +1180,16 @@ 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 0db899e..0b30750 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -617,16 +617,10 @@ int vm_event_domctl(struct domain *d, xen_domctl_vm_event_op_t *vec, switch( vec->op ) { case XEN_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE: - case XEN_DOMCTL_VM_EVENT_OP_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_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE_INTROSPECTION - && !rc ) - p2m_setup_introspection(d); - } break; @@ -635,7 +629,6 @@ int vm_event_domctl(struct domain *d, xen_domctl_vm_event_op_t *vec, if ( ved->ring_page ) { rc = vm_event_disable(d, ved); - d->arch.hvm_domain.introspection_enabled = 0; } } break; 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 20ede1e..99fcd94 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -236,6 +236,41 @@ struct time_scale { u32 mul_frac; }; +/************************************************/ +/* monitor event options */ +/************************************************/ +struct mov_to_cr0 { + uint8_t enabled; + uint8_t sync; + uint8_t onchangeonly; +}; + +struct mov_to_cr3 { + uint8_t enabled; + uint8_t sync; + uint8_t onchangeonly; +}; + +struct mov_to_cr4 { + uint8_t enabled; + uint8_t sync; + uint8_t onchangeonly; +}; + +struct mov_to_msr { + uint8_t enabled; + uint8_t extended_capture; +}; + +struct singlestep { + uint8_t enabled; +}; + +struct software_breakpoint { + uint8_t enabled; +}; + + struct pv_domain { l1_pgentry_t **gdt_ldt_l1tab; @@ -330,6 +365,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_cr0 mov_to_cr0; + struct mov_to_cr3 mov_to_cr3; + struct mov_to_cr4 mov_to_cr4; + struct mov_to_msr mov_to_msr; + struct singlestep singlestep; + struct software_breakpoint software_breakpoint; + } monitor_options; } __cacheline_aligned; #define has_arch_pdevs(d) (!list_empty(&(d)->arch.pdev_list)) diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h new file mode 100644 index 0000000..1d7cdd3 --- /dev/null +++ b/xen/include/asm-x86/monitor.h @@ -0,0 +1,9 @@ +#ifndef __ASM_X86_MONITOR_H__ +#define __ASM_X86_MONITOR_H__ + +#include <xen/config.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 5d48a4d..4f3b685 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -803,7 +803,6 @@ struct xen_domctl_gdbsx_domstatus { #define XEN_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE 0 #define XEN_DOMCTL_VM_EVENT_OP_MONITOR_DISABLE 1 -#define XEN_DOMCTL_VM_EVENT_OP_MONITOR_ENABLE_INTROSPECTION 2 /* * Sharing ENOMEM helper. @@ -1001,6 +1000,58 @@ 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 { + uint8_t sync; /* Pause vCPU until response */ + uint8_t onchangeonly; /* Send event only on a change of value */ + uint8_t pad[6]; + } mov_to_cr0, mov_to_cr3, mov_to_cr4; + + /* Enable the capture of msr events on + MSR_IA32_SYSENTER_EIP + MSR_IA32_SYSENTER_ESP + MSR_IA32_SYSENTER_CS + MSR_IA32_MC0_CTL + MSR_STAR + MSR_LSTAR */ + struct { + uint8_t extended_capture; + uint8_t pad[7]; + } mov_to_msr; + } options; +}; +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 +1127,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 +1193,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 8fba3d1b..a057608 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 9 /* Debug operation executed (int3) */ #define VM_EVENT_REASON_SOFTWARE_BREAKPOINT 7 -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |