This patch implements event channel tapping. If an inter-domain channel is set
to ECS_TAP, it calls the function registered when an event is sent to the
channel.
Signed-off-by: Yoshi Tamura <tamura.yoshiaki@xxxxxxxxxxxxx>
Signed-off-by: Yoshisato Yanagisawa <yanagisawa.yoshisato@xxxxxxxxxxxxx>
---
xen/common/event_channel.c | 150 ++++++++++++++++++++++++++++++++++++++++++++-
xen/include/xen/event.h | 14 ++++
xen/include/xen/sched.h | 10 +++
3 files changed, 173 insertions(+), 1 deletion(-)
diff -r 19201eebab16 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Thu Sep 25 13:33:50 2008 +0100
+++ b/xen/include/xen/sched.h Wed Mar 04 17:04:30 2009 +0900
@@ -19,6 +19,7 @@
#include <xen/xenoprof.h>
#include <xen/rcupdate.h>
#include <xen/irq.h>
+#include <xen/kemari.h>
#ifdef CONFIG_COMPAT
#include <compat/vcpu.h>
@@ -47,6 +48,7 @@
#define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */
#define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */
#define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */
+#define ECS_TAP 7 /* Channel is bound and tapped. */
u8 state; /* ECS_* */
u8 consumer_is_xen; /* Consumed by Xen or by guest? */
u16 notify_vcpu_id; /* VCPU for local delivery notification */
@@ -61,6 +63,11 @@
u16 pirq; /* state == ECS_PIRQ */
u16 virq; /* state == ECS_VIRQ */
} u;
+ struct {
+ u8 mode; /* Tap IN, OUT or both. */
+ /* Fucntion to call when an event is detected. */
+ long (*redirect) (struct evtchn *lchn, struct evtchn *rchn);
+ } tap;
#ifdef FLASK_ENABLE
void *ssid;
#endif
@@ -249,6 +256,9 @@
/* OProfile support. */
struct xenoprof *xenoprof;
int32_t time_offset_seconds;
+
+ /* Kemari support. */
+ struct kemari *kemari;
struct rcu_head rcu;
diff -r 19201eebab16 xen/include/xen/event.h
--- a/xen/include/xen/event.h Thu Sep 25 13:33:50 2008 +0100
+++ b/xen/include/xen/event.h Wed Mar 04 17:04:30 2009 +0900
@@ -79,4 +79,18 @@
mb(); /* set blocked status /then/ caller does his work */ \
} while ( 0 )
+struct evtchn_bind_tap {
+ /* IN parameters. */
+ domid_t tap_dom;
+ uint32_t tap_port;
+ uint8_t mode;
+ long (*redirect) (struct evtchn *lchn, struct evtchn *rchn);
+};
+
+void notify_via_xen_evtchn_tap(struct domain *ld, int lport);
+
+long evtchn_bind_tap(struct evtchn_bind_tap *bind_tap);
+
+long evtchn_unbind_tap(struct evtchn_bind_tap *bind_tap);
+
#endif /* __XEN_EVENT_H__ */
diff -r 19201eebab16 xen/common/event_channel.c
--- a/xen/common/event_channel.c Thu Sep 25 13:33:50 2008 +0100
+++ b/xen/common/event_channel.c Wed Mar 04 17:04:28 2009 +0900
@@ -201,7 +201,8 @@
if ( !port_is_valid(rd, rport) )
ERROR_EXIT_DOM(-EINVAL, rd);
rchn = evtchn_from_port(rd, rport);
- if ( (rchn->state != ECS_UNBOUND) ||
+ /* kemari needs to reuse rchn information */
+ if ( (rchn->state != ECS_UNBOUND) &&
(rchn->u.unbound.remote_domid != ld->domain_id) )
ERROR_EXIT_DOM(-EINVAL, rd);
@@ -348,6 +349,113 @@
return rc;
}
+long evtchn_bind_tap(struct evtchn_bind_tap *bind_tap)
+{
+ struct evtchn *lchn, *rchn;
+ struct domain *ld, *rd;
+ int lport = bind_tap->tap_port, rport;
+ domid_t ldom = bind_tap->tap_dom;
+ long ret;
+
+ if ( (ld = rcu_lock_domain_by_id(ldom)) == NULL )
+ return -ESRCH;
+
+ spin_lock(&ld->evtchn_lock);
+
+ ret = -EINVAL;
+ if ( !port_is_valid(ld, lport) )
+ goto lchn_out;
+ lchn = evtchn_from_port(ld, lport);
+ if ( lchn->state != ECS_INTERDOMAIN )
+ goto lchn_out;
+
+ ret = -ESRCH;
+ rd = lchn->u.interdomain.remote_dom;
+ if ( rd == NULL )
+ goto lchn_out;
+
+ spin_lock(&rd->evtchn_lock);
+
+ rport = lchn->u.interdomain.remote_port;
+ if ( !port_is_valid(rd, rport) )
+ goto rchn_out;
+ rchn = evtchn_from_port(rd, rport);
+ if ( rchn->state != ECS_INTERDOMAIN )
+ goto rchn_out;
+
+ lchn->state = ECS_TAP;
+ lchn->tap.mode = bind_tap->mode;
+ lchn->tap.redirect = bind_tap->redirect;
+
+ rchn->state = ECS_TAP;
+ rchn->tap.redirect = bind_tap->redirect;
+
+ ret = 0;
+
+ rchn_out:
+ spin_unlock(&rd->evtchn_lock);
+
+ lchn_out:
+ spin_unlock(&ld->evtchn_lock);
+
+ rcu_unlock_domain(ld);
+
+ return ret;
+}
+
+long evtchn_unbind_tap(struct evtchn_bind_tap *bind_tap)
+{
+ struct evtchn *lchn, *rchn;
+ struct domain *ld, *rd;
+ int lport = bind_tap->tap_port, rport;
+ domid_t ldom = bind_tap->tap_dom;
+ long ret;
+
+ if ( (ld = rcu_lock_domain_by_id(ldom)) == NULL )
+ return -ESRCH;
+
+ spin_lock(&ld->evtchn_lock);
+
+ ret = -EINVAL;
+ if ( !port_is_valid(ld, lport) )
+ goto lchn_out;
+ lchn = evtchn_from_port(ld, lport);
+ if ( lchn->state != ECS_TAP )
+ goto lchn_out;
+
+ ret = -ESRCH;
+ rd = lchn->u.interdomain.remote_dom;
+ if ( rd == NULL )
+ goto lchn_out;
+
+ spin_lock(&rd->evtchn_lock);
+
+ rport = lchn->u.interdomain.remote_port;
+ if ( !port_is_valid(rd, rport) )
+ goto rchn_out;
+ rchn = evtchn_from_port(rd, rport);
+ if ( rchn->state != ECS_TAP )
+ goto rchn_out;
+
+ lchn->state = ECS_INTERDOMAIN;
+ lchn->tap.mode = bind_tap->mode;
+ lchn->tap.redirect = NULL;
+
+ rchn->state = ECS_INTERDOMAIN;
+ rchn->tap.redirect = NULL;
+
+ ret = 0;
+
+ rchn_out:
+ spin_unlock(&rd->evtchn_lock);
+
+ lchn_out:
+ spin_unlock(&ld->evtchn_lock);
+
+ rcu_unlock_domain(ld);
+
+ return ret;
+}
static long __evtchn_close(struct domain *d1, int port1)
{
@@ -403,6 +511,7 @@
case ECS_IPI:
break;
+ case ECS_TAP:
case ECS_INTERDOMAIN:
if ( d2 == NULL )
{
@@ -440,6 +549,14 @@
BUG_ON(!port_is_valid(d2, port2));
chn2 = evtchn_from_port(d2, port2);
+
+ if ( chn1->state == ECS_TAP )
+ {
+ chn1->tap.redirect = NULL;
+ chn2->tap.redirect = NULL;
+ chn2->state = ECS_INTERDOMAIN;
+ }
+
BUG_ON(chn2->state != ECS_INTERDOMAIN);
BUG_ON(chn2->u.interdomain.remote_dom != d1);
@@ -509,6 +626,13 @@
switch ( lchn->state )
{
+ case ECS_TAP:
+ rd = lchn->u.interdomain.remote_dom;
+ rport = lchn->u.interdomain.remote_port;
+ rchn = evtchn_from_port(rd, rport);
+
+ lchn->tap.redirect(lchn, rchn);
+
case ECS_INTERDOMAIN:
rd = lchn->u.interdomain.remote_dom;
rport = lchn->u.interdomain.remote_port;
@@ -1037,6 +1161,30 @@
spin_unlock(&ld->evtchn_lock);
}
+void notify_via_xen_evtchn_tap(struct domain *ld, int lport)
+{
+ struct evtchn *lchn, *rchn;
+ struct domain *rd;
+ int rport;
+
+ if (ld != current->domain)
+ spin_lock(&ld->evtchn_lock);
+
+ ASSERT(port_is_valid(ld, lport));
+ lchn = evtchn_from_port(ld, lport);
+ ASSERT(lchn->consumer_is_xen);
+
+ if ( likely(lchn->state == ECS_INTERDOMAIN) )
+ {
+ rd = lchn->u.interdomain.remote_dom;
+ rport = lchn->u.interdomain.remote_port;
+ rchn = evtchn_from_port(rd, rport);
+ evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
+ }
+
+ if (ld != current->domain)
+ spin_unlock(&ld->evtchn_lock);
+}
int evtchn_init(struct domain *d)
{
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|