mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/vm-events: Move parts of monitor_domctl code to common-side.
This patch moves monitor_domctl to common-side. Purpose: move what's common to common, prepare for implementation of such vm-events on ARM. * move get_capabilities to arch-side => arch_monitor_get_capabilities. * add arch-side monitor op handling function => arch_monitor_domctl_op. e.g. X86-side handles XEN_DOMCTL_MONITOR_OP_EMULATE_EACH_REP op * add arch-side monitor event handling function => arch_monitor_domctl_event. e.g. X86-side handles XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR event enable/disable * remove status_check Signed-off-by: Corneliu ZUZU <czuzu@bitdefender.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
This commit is contained in:
1 parent
46944ac869
commit
f5365e6a17
8 files changed
+218
-123
No files matched your search
@@ -355,6 +355,7 @@ M: Tamas K Lengyel <tamas@tklengyel.com>
|
||||
S: Supported
|
||||
F: xen/common/vm_event.c
|
||||
F: xen/common/mem_access.c
|
||||
F: xen/common/monitor.c
|
||||
F: xen/arch/x86/hvm/event.c
|
||||
F: xen/arch/x86/monitor.c
|
||||
F: xen/arch/*/vm_event.c
|
||||
|
||||
+40
-113
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* arch/x86/monitor.c
|
||||
*
|
||||
* Architecture-specific monitor_op domctl handler.
|
||||
* Arch-specific monitor_op domctl handler.
|
||||
*
|
||||
* Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
|
||||
* Copyright (c) 2016, Bitdefender S.R.L.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
@@ -18,87 +19,14 @@
|
||||
* License along with this program; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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>
|
||||
#include <public/vm_event.h>
|
||||
|
||||
/*
|
||||
* Sanity check whether option is already enabled/disabled
|
||||
*/
|
||||
static inline
|
||||
int status_check(struct xen_domctl_monitor_op *mop, bool_t status)
|
||||
int arch_monitor_domctl_event(struct domain *d,
|
||||
struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
bool_t requested_status = (mop->op == XEN_DOMCTL_MONITOR_OP_ENABLE);
|
||||
|
||||
if ( status == requested_status )
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t get_capabilities(struct domain *d)
|
||||
{
|
||||
uint32_t capabilities = 0;
|
||||
|
||||
/*
|
||||
* 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 capabilities;
|
||||
|
||||
capabilities = (1 << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST);
|
||||
|
||||
/* Since we know this is on VMX, we can just call the hvm func */
|
||||
if ( hvm_is_singlestep_supported() )
|
||||
capabilities |= (1 << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP);
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
int rc;
|
||||
struct arch_domain *ad = &d->arch;
|
||||
uint32_t capabilities = get_capabilities(d);
|
||||
|
||||
if ( current->domain == d ) /* no domain_pause() */
|
||||
return -EPERM;
|
||||
|
||||
rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
switch ( mop->op )
|
||||
{
|
||||
case XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES:
|
||||
mop->event = capabilities;
|
||||
return 0;
|
||||
|
||||
case XEN_DOMCTL_MONITOR_OP_EMULATE_EACH_REP:
|
||||
domain_pause(d);
|
||||
ad->mem_access_emulate_each_rep = !!mop->event;
|
||||
domain_unpause(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check
|
||||
*/
|
||||
if ( mop->op != XEN_DOMCTL_MONITOR_OP_ENABLE &&
|
||||
mop->op != XEN_DOMCTL_MONITOR_OP_DISABLE )
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Check if event type is available. */
|
||||
if ( !(capabilities & (1 << mop->event)) )
|
||||
return -EOPNOTSUPP;
|
||||
bool_t requested_status = (XEN_DOMCTL_MONITOR_OP_ENABLE == mop->op);
|
||||
|
||||
switch ( mop->event )
|
||||
{
|
||||
@@ -106,13 +34,11 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
unsigned int ctrlreg_bitmask =
|
||||
monitor_ctrlreg_bitmask(mop->u.mov_to_cr.index);
|
||||
bool_t status =
|
||||
bool_t old_status =
|
||||
!!(ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask);
|
||||
struct vcpu *v;
|
||||
|
||||
rc = status_check(mop, status);
|
||||
if ( rc )
|
||||
return rc;
|
||||
if ( unlikely(old_status == requested_status) )
|
||||
return -EEXIST;
|
||||
|
||||
domain_pause(d);
|
||||
|
||||
@@ -126,15 +52,18 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
else
|
||||
ad->monitor.write_ctrlreg_onchangeonly &= ~ctrlreg_bitmask;
|
||||
|
||||
if ( !status )
|
||||
if ( requested_status )
|
||||
ad->monitor.write_ctrlreg_enabled |= ctrlreg_bitmask;
|
||||
else
|
||||
ad->monitor.write_ctrlreg_enabled &= ~ctrlreg_bitmask;
|
||||
|
||||
if ( mop->u.mov_to_cr.index == VM_EVENT_X86_CR3 )
|
||||
/* Latches new CR3 mask through CR0 code */
|
||||
if ( VM_EVENT_X86_CR3 == mop->u.mov_to_cr.index )
|
||||
{
|
||||
struct vcpu *v;
|
||||
/* Latches new CR3 mask through CR0 code. */
|
||||
for_each_vcpu ( d, v )
|
||||
hvm_update_guest_cr(v, 0);
|
||||
}
|
||||
|
||||
domain_unpause(d);
|
||||
|
||||
@@ -143,77 +72,75 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
|
||||
case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR:
|
||||
{
|
||||
bool_t status = ad->monitor.mov_to_msr_enabled;
|
||||
bool_t old_status = ad->monitor.mov_to_msr_enabled;
|
||||
|
||||
rc = status_check(mop, status);
|
||||
if ( rc )
|
||||
return rc;
|
||||
if ( unlikely(old_status == requested_status) )
|
||||
return -EEXIST;
|
||||
|
||||
if ( mop->op == XEN_DOMCTL_MONITOR_OP_ENABLE &&
|
||||
mop->u.mov_to_msr.extended_capture &&
|
||||
if ( requested_status && mop->u.mov_to_msr.extended_capture &&
|
||||
!hvm_enable_msr_exit_interception(d) )
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
domain_pause(d);
|
||||
|
||||
if ( mop->op == XEN_DOMCTL_MONITOR_OP_ENABLE &&
|
||||
mop->u.mov_to_msr.extended_capture )
|
||||
ad->monitor.mov_to_msr_extended = 1;
|
||||
if ( requested_status && mop->u.mov_to_msr.extended_capture )
|
||||
ad->monitor.mov_to_msr_extended = 1;
|
||||
else
|
||||
ad->monitor.mov_to_msr_extended = 0;
|
||||
|
||||
ad->monitor.mov_to_msr_enabled = !status;
|
||||
ad->monitor.mov_to_msr_enabled = requested_status;
|
||||
domain_unpause(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP:
|
||||
{
|
||||
bool_t status = ad->monitor.singlestep_enabled;
|
||||
bool_t old_status = ad->monitor.singlestep_enabled;
|
||||
|
||||
rc = status_check(mop, status);
|
||||
if ( rc )
|
||||
return rc;
|
||||
if ( unlikely(old_status == requested_status) )
|
||||
return -EEXIST;
|
||||
|
||||
domain_pause(d);
|
||||
ad->monitor.singlestep_enabled = !status;
|
||||
ad->monitor.singlestep_enabled = requested_status;
|
||||
domain_unpause(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT:
|
||||
{
|
||||
bool_t status = ad->monitor.software_breakpoint_enabled;
|
||||
bool_t old_status = ad->monitor.software_breakpoint_enabled;
|
||||
|
||||
rc = status_check(mop, status);
|
||||
if ( rc )
|
||||
return rc;
|
||||
if ( unlikely(old_status == requested_status) )
|
||||
return -EEXIST;
|
||||
|
||||
domain_pause(d);
|
||||
ad->monitor.software_breakpoint_enabled = !status;
|
||||
ad->monitor.software_breakpoint_enabled = requested_status;
|
||||
domain_unpause(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST:
|
||||
{
|
||||
bool_t status = ad->monitor.guest_request_enabled;
|
||||
bool_t old_status = ad->monitor.guest_request_enabled;
|
||||
|
||||
rc = status_check(mop, status);
|
||||
if ( rc )
|
||||
return rc;
|
||||
if ( unlikely(old_status == requested_status) )
|
||||
return -EEXIST;
|
||||
|
||||
domain_pause(d);
|
||||
ad->monitor.guest_request_sync = mop->u.guest_request.sync;
|
||||
ad->monitor.guest_request_enabled = !status;
|
||||
ad->monitor.guest_request_enabled = requested_status;
|
||||
domain_unpause(d);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/*
|
||||
* Should not be reached unless arch_monitor_get_capabilities() is not
|
||||
* properly implemented.
|
||||
*/
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ obj-y += lib.o
|
||||
obj-y += lzo.o
|
||||
obj-$(CONFIG_HAS_MEM_ACCESS) += mem_access.o
|
||||
obj-y += memory.o
|
||||
obj-y += monitor.o
|
||||
obj-y += multicall.o
|
||||
obj-y += notifier.o
|
||||
obj-y += page_alloc.o
|
||||
|
||||
+1
-1
@@ -25,11 +25,11 @@
|
||||
#include <xen/paging.h>
|
||||
#include <xen/hypercall.h>
|
||||
#include <xen/vm_event.h>
|
||||
#include <xen/monitor.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/p2m.h>
|
||||
#include <asm/monitor.h>
|
||||
#include <public/domctl.h>
|
||||
#include <xsm/xsm.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* xen/common/monitor.c
|
||||
*
|
||||
* Common monitor_op domctl handler.
|
||||
*
|
||||
* Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
|
||||
* Copyright (c) 2016, Bitdefender S.R.L.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <xen/monitor.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xsm/xsm.h>
|
||||
#include <public/domctl.h>
|
||||
#include <asm/monitor.h>
|
||||
|
||||
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ( unlikely(current->domain == d) ) /* no domain_pause() */
|
||||
return -EPERM;
|
||||
|
||||
rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event);
|
||||
if ( unlikely(rc) )
|
||||
return rc;
|
||||
|
||||
switch ( mop->op )
|
||||
{
|
||||
case XEN_DOMCTL_MONITOR_OP_ENABLE:
|
||||
case XEN_DOMCTL_MONITOR_OP_DISABLE:
|
||||
/* Check if event type is available. */
|
||||
/* sanity check: avoid left-shift undefined behavior */
|
||||
if ( unlikely(mop->event > 31) )
|
||||
return -EINVAL;
|
||||
if ( unlikely(!(arch_monitor_get_capabilities(d) & (1U << mop->event))) )
|
||||
return -EOPNOTSUPP;
|
||||
/* Arch-side handles enable/disable ops. */
|
||||
return arch_monitor_domctl_event(d, mop);
|
||||
|
||||
case XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES:
|
||||
mop->event = arch_monitor_get_capabilities(d);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/* The monitor op is probably handled on the arch-side. */
|
||||
return arch_monitor_domctl_op(d, mop);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-file-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* include/asm-arm/monitor.h
|
||||
*
|
||||
* Architecture-specific monitor_op domctl handler.
|
||||
* Arch-specific monitor_op domctl handler.
|
||||
*
|
||||
* Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
|
||||
* Copyright (c) 2016, Bitdefender S.R.L.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
@@ -24,10 +25,31 @@
|
||||
#include <xen/sched.h>
|
||||
#include <public/domctl.h>
|
||||
|
||||
static inline
|
||||
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op)
|
||||
static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
|
||||
{
|
||||
return -ENOSYS;
|
||||
/* No monitor vm-events implemented on ARM. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __ASM_X86_MONITOR_H__ */
|
||||
static inline
|
||||
int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
/* No arch-specific monitor ops on ARM. */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline
|
||||
int arch_monitor_domctl_event(struct domain *d,
|
||||
struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
/*
|
||||
* No arch-specific monitor vm-events on ARM.
|
||||
*
|
||||
* Should not be reached unless arch_monitor_get_capabilities() is not
|
||||
* properly implemented.
|
||||
*/
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* __ASM_ARM_MONITOR_H__ */
|
||||
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* include/asm-x86/monitor.h
|
||||
*
|
||||
* Architecture-specific monitor_op domctl handler.
|
||||
* Arch-specific monitor_op domctl handler.
|
||||
*
|
||||
* Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
|
||||
* Copyright (c) 2016, Bitdefender S.R.L.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
@@ -21,11 +22,55 @@
|
||||
#ifndef __ASM_X86_MONITOR_H__
|
||||
#define __ASM_X86_MONITOR_H__
|
||||
|
||||
struct domain;
|
||||
struct xen_domctl_monitor_op;
|
||||
#include <xen/sched.h>
|
||||
#include <public/domctl.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/hvm/hvm.h>
|
||||
|
||||
#define monitor_ctrlreg_bitmask(ctrlreg_index) (1U << (ctrlreg_index))
|
||||
|
||||
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op);
|
||||
static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
|
||||
{
|
||||
uint32_t capabilities = 0;
|
||||
|
||||
/*
|
||||
* 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 capabilities;
|
||||
|
||||
capabilities = (1 << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT) |
|
||||
(1 << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST);
|
||||
|
||||
/* Since we know this is on VMX, we can just call the hvm func */
|
||||
if ( hvm_is_singlestep_supported() )
|
||||
capabilities |= (1 << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP);
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
static inline
|
||||
int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
|
||||
{
|
||||
switch ( mop->op )
|
||||
{
|
||||
case XEN_DOMCTL_MONITOR_OP_EMULATE_EACH_REP:
|
||||
domain_pause(d);
|
||||
d->arch.mem_access_emulate_each_rep = !!mop->event;
|
||||
domain_unpause(d);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_monitor_domctl_event(struct domain *d,
|
||||
struct xen_domctl_monitor_op *mop);
|
||||
|
||||
#endif /* __ASM_X86_MONITOR_H__ */
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* include/xen/monitor.h
|
||||
*
|
||||
* Common monitor_op domctl handler.
|
||||
*
|
||||
* Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
|
||||
* Copyright (c) 2016, Bitdefender S.R.L.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XEN_MONITOR_H__
|
||||
#define __XEN_MONITOR_H__
|
||||
|
||||
struct domain;
|
||||
struct xen_domctl_monitor_op;
|
||||
|
||||
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op);
|
||||
|
||||
#endif /* __XEN_MONITOR_H__ */
|
||||