diff -r ade44be5b936 xen/arch/ia64/vmx/vmx_init.c --- a/xen/arch/ia64/vmx/vmx_init.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/arch/ia64/vmx/vmx_init.c Fri Sep 30 20:37:02 2011 +0100 @@ -377,7 +377,7 @@ vmx_vcpu_initialise(struct vcpu *v) { struct vmx_ioreq_page *iorp = &v->domain->arch.hvm_domain.ioreq; - int rc = alloc_unbound_xen_event_channel(v, 0); + int rc = alloc_unbound_xen_event_channel(v, 0, NULL); if (rc < 0) return rc; v->arch.arch_vmx.xen_port = rc; diff -r ade44be5b936 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/arch/x86/hvm/hvm.c Fri Sep 30 20:37:02 2011 +0100 @@ -970,7 +970,7 @@ int hvm_vcpu_initialise(struct vcpu *v) goto fail3; /* Create ioreq event channel. */ - rc = alloc_unbound_xen_event_channel(v, 0); + rc = alloc_unbound_xen_event_channel(v, 0, NULL); if ( rc < 0 ) goto fail4; @@ -3477,7 +3477,8 @@ long do_hvm_op(unsigned long op, XEN_GUE for_each_vcpu ( d, v ) { int old_port, new_port; - new_port = alloc_unbound_xen_event_channel(v, a.value); + new_port = alloc_unbound_xen_event_channel( + v, a.value, NULL); if ( new_port < 0 ) { rc = new_port; diff -r ade44be5b936 xen/arch/x86/mm/mem_access.c --- a/xen/arch/x86/mm/mem_access.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/arch/x86/mm/mem_access.c Fri Sep 30 20:37:02 2011 +0100 @@ -29,13 +29,12 @@ int mem_access_domctl(struct domain *d, XEN_GUEST_HANDLE(void) u_domctl) { int rc; - struct p2m_domain *p2m = p2m_get_hostp2m(d); switch( mec->op ) { case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_RESUME: { - p2m_mem_access_resume(p2m); + p2m_mem_access_resume(d); rc = 0; } break; diff -r ade44be5b936 xen/arch/x86/mm/mem_event.c --- a/xen/arch/x86/mm/mem_event.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/arch/x86/mm/mem_event.c Fri Sep 30 20:37:02 2011 +0100 @@ -37,9 +37,11 @@ #define mem_event_ring_lock(_med) spin_lock(&(_med)->ring_lock) #define mem_event_ring_unlock(_med) spin_unlock(&(_med)->ring_lock) -static int mem_event_enable(struct domain *d, - xen_domctl_mem_event_op_t *mec, - struct mem_event_domain *med) +static int mem_event_enable( + struct domain *d, + xen_domctl_mem_event_op_t *mec, + struct mem_event_domain *med, + xen_event_channel_notification_t notification_fn) { int rc; struct domain *dom_mem_event = current->domain; @@ -79,8 +81,8 @@ static int mem_event_enable(struct domai med->shared_page = map_domain_page(mfn_x(shared_mfn)); /* Allocate event channel */ - rc = alloc_unbound_xen_event_channel(d->vcpu[0], - current->domain->domain_id); + rc = alloc_unbound_xen_event_channel( + d->vcpu[0], current->domain->domain_id, notification_fn); if ( rc < 0 ) goto err; @@ -213,6 +215,18 @@ int mem_event_check_ring(struct domain * return ring_full; } +/* Registered with Xen-bound event channel for incoming notifications. */ +static void mem_paging_notification(struct vcpu *v, unsigned int port) +{ + p2m_mem_paging_resume(v->domain); +} + +/* Registered with Xen-bound event channel for incoming notifications. */ +static void mem_access_notification(struct vcpu *v, unsigned int port) +{ + p2m_mem_access_resume(v->domain); +} + int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, XEN_GUEST_HANDLE(void) u_domctl) { @@ -266,7 +280,7 @@ int mem_event_domctl(struct domain *d, x { case XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE: { - rc = mem_event_enable(d, mec, med); + rc = mem_event_enable(d, mec, med, mem_paging_notification); } break; @@ -302,7 +316,7 @@ int mem_event_domctl(struct domain *d, x { case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE: { - rc = mem_event_enable(d, mec, med); + rc = mem_event_enable(d, mec, med, mem_access_notification); } break; diff -r ade44be5b936 xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/arch/x86/mm/p2m.c Fri Sep 30 20:37:02 2011 +0100 @@ -943,9 +943,8 @@ void p2m_mem_access_check(unsigned long /* VCPU paused, mem event request sent */ } -void p2m_mem_access_resume(struct p2m_domain *p2m) +void p2m_mem_access_resume(struct domain *d) { - struct domain *d = p2m->domain; mem_event_response_t rsp; mem_event_get_response(&d->mem_access, &rsp); diff -r ade44be5b936 xen/common/event_channel.c --- a/xen/common/event_channel.c Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/common/event_channel.c Fri Sep 30 20:37:02 2011 +0100 @@ -57,6 +57,51 @@ goto out; \ } while ( 0 ) +#define consumer_is_xen(e) (!!(e)->xen_consumer) + +/* + * The function alloc_unbound_xen_event_channel() allows an arbitrary + * notifier function to be specified. However, very few unique functions + * are specified in practice, so to prevent bloating the evtchn structure + * with a pointer, we stash them dynamically in a small lookup array which + * can be indexed by a small integer. + */ +static xen_event_channel_notification_t xen_consumers[8]; + +/* Default notification action: wake up from wait_on_xen_event_channel(). */ +static void default_xen_notification_fn(struct vcpu *v, unsigned int port) +{ + /* Consumer needs notification only if blocked. */ + if ( test_and_clear_bit(_VPF_blocked_in_xen, &v->pause_flags) ) + vcpu_wake(v); +} + +/* + * Given a notification function, return the value to stash in + * the evtchn->xen_consumer field. + */ +static uint8_t get_xen_consumer(xen_event_channel_notification_t fn) +{ + unsigned int i; + + if ( fn == NULL ) + fn = default_xen_notification_fn; + + for ( i = 0; i < ARRAY_SIZE(xen_consumers); i++ ) + { + if ( xen_consumers[i] == NULL ) + xen_consumers[i] = fn; + if ( xen_consumers[i] == fn ) + break; + } + + BUG_ON(i >= ARRAY_SIZE(xen_consumers)); + return i+1; +} + +/* Get the notification function for a given Xen-bound event channel. */ +#define xen_notification_fn(e) (xen_consumers[(e)->xen_consumer-1]) + static int evtchn_set_pending(struct vcpu *v, int port); static int virq_is_global(int virq) @@ -396,7 +441,7 @@ static long __evtchn_close(struct domain chn1 = evtchn_from_port(d1, port1); /* Guest cannot close a Xen-attached event channel. */ - if ( unlikely(chn1->consumer_is_xen) ) + if ( unlikely(consumer_is_xen(chn1)) ) { rc = -EINVAL; goto out; @@ -534,7 +579,7 @@ int evtchn_send(struct domain *d, unsign lchn = evtchn_from_port(ld, lport); /* Guest cannot send via a Xen-attached event channel. */ - if ( unlikely(lchn->consumer_is_xen) ) + if ( unlikely(consumer_is_xen(lchn)) ) { spin_unlock(&ld->event_lock); return -EINVAL; @@ -551,13 +596,8 @@ int evtchn_send(struct domain *d, unsign rport = lchn->u.interdomain.remote_port; rchn = evtchn_from_port(rd, rport); rvcpu = rd->vcpu[rchn->notify_vcpu_id]; - if ( rchn->consumer_is_xen ) - { - /* Xen consumers need notification only if they are blocked. */ - if ( test_and_clear_bit(_VPF_blocked_in_xen, - &rvcpu->pause_flags) ) - vcpu_wake(rvcpu); - } + if ( consumer_is_xen(rchn) ) + (*xen_notification_fn(rchn))(rvcpu, rport); else { evtchn_set_pending(rvcpu, rport); @@ -784,7 +824,7 @@ long evtchn_bind_vcpu(unsigned int port, chn = evtchn_from_port(d, port); /* Guest cannot re-bind a Xen-attached event channel. */ - if ( unlikely(chn->consumer_is_xen) ) + if ( unlikely(consumer_is_xen(chn)) ) { rc = -EINVAL; goto out; @@ -995,7 +1035,8 @@ long do_event_channel_op(int cmd, XEN_GU int alloc_unbound_xen_event_channel( - struct vcpu *local_vcpu, domid_t remote_domid) + struct vcpu *local_vcpu, domid_t remote_domid, + xen_event_channel_notification_t notification_fn) { struct evtchn *chn; struct domain *d = local_vcpu->domain; @@ -1008,7 +1049,7 @@ int alloc_unbound_xen_event_channel( chn = evtchn_from_port(d, port); chn->state = ECS_UNBOUND; - chn->consumer_is_xen = 1; + chn->xen_consumer = get_xen_consumer(notification_fn); chn->notify_vcpu_id = local_vcpu->vcpu_id; chn->u.unbound.remote_domid = remote_domid; @@ -1035,8 +1076,8 @@ void free_xen_event_channel( BUG_ON(!port_is_valid(d, port)); chn = evtchn_from_port(d, port); - BUG_ON(!chn->consumer_is_xen); - chn->consumer_is_xen = 0; + BUG_ON(!consumer_is_xen(chn)); + chn->xen_consumer = 0; spin_unlock(&d->event_lock); @@ -1060,7 +1101,7 @@ void notify_via_xen_event_channel(struct ASSERT(port_is_valid(ld, lport)); lchn = evtchn_from_port(ld, lport); - ASSERT(lchn->consumer_is_xen); + ASSERT(consumer_is_xen(lchn)); if ( likely(lchn->state == ECS_INTERDOMAIN) ) { @@ -1103,7 +1144,7 @@ void evtchn_destroy(struct domain *d) /* Close all existing event channels. */ for ( i = 0; port_is_valid(d, i); i++ ) { - evtchn_from_port(d, i)->consumer_is_xen = 0; + evtchn_from_port(d, i)->xen_consumer = 0; (void)__evtchn_close(d, i); } @@ -1189,7 +1230,7 @@ static void domain_dump_evtchn_info(stru printk(" v=%d", chn->u.virq); break; } - printk(" x=%d\n", chn->consumer_is_xen); + printk(" x=%d\n", chn->xen_consumer); } spin_unlock(&d->event_lock); diff -r ade44be5b936 xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/include/asm-x86/p2m.h Fri Sep 30 20:37:02 2011 +0100 @@ -503,7 +503,7 @@ static inline void p2m_mem_paging_popula void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long gla, bool_t access_r, bool_t access_w, bool_t access_x); /* Resumes the running of the VCPU, restarting the last instruction */ -void p2m_mem_access_resume(struct p2m_domain *p2m); +void p2m_mem_access_resume(struct domain *d); /* Set access type for a region of pfns. * If start_pfn == -1ul, sets the default access type */ diff -r ade44be5b936 xen/include/xen/event.h --- a/xen/include/xen/event.h Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/include/xen/event.h Fri Sep 30 20:37:02 2011 +0100 @@ -51,8 +51,11 @@ int evtchn_unmask(unsigned int port); void evtchn_move_pirqs(struct vcpu *v); /* Allocate/free a Xen-attached event channel port. */ +typedef void (*xen_event_channel_notification_t)( + struct vcpu *v, unsigned int port); int alloc_unbound_xen_event_channel( - struct vcpu *local_vcpu, domid_t remote_domid); + struct vcpu *local_vcpu, domid_t remote_domid, + xen_event_channel_notification_t notification_fn); void free_xen_event_channel( struct vcpu *local_vcpu, int port); diff -r ade44be5b936 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Tue Sep 27 16:15:09 2011 +0100 +++ b/xen/include/xen/sched.h Fri Sep 30 20:37:02 2011 +0100 @@ -47,7 +47,7 @@ struct evtchn #define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */ #define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */ u8 state; /* ECS_* */ - u8 consumer_is_xen; /* Consumed by Xen or by guest? */ + u8 xen_consumer; /* Consumer in Xen, if any? (0 = send to guest) */ u16 notify_vcpu_id; /* VCPU for local delivery notification */ union { struct {