Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 00/15] Implement 3-level event channel ABI in Xen
This is the 5th RFC series (in fact 6th because I dropped RFC in one of the series I posted) for the 3-level event channel design. Changes since V4: * Rework internal event channel object store to optimize memory usage. * Switch back to function pointers, because it has the same (or less) performance degradation compared to ''switch'' statement, while at the same time it allows for clearer code structure. * Separate internal event channel inteface and ABI implementation. * Only enable 3-level event channel for Dom0, this should be a good starting point for testing. The toolstack integration is left open. * A compat shim is missing, but should be trivial to add. Changes since V3: * Dedicated EVTCHNOP for extended ABI query * Dedicated EVTCHNOP for 3-level ABI registration * 3-level ABI is registered in two phases: * register the bitmaps * register per-cpu L2 selector * libxl: evtchn_extended -> evtchn_extended_allowed Changes since V2: * new interface to register extended event channel ABI * use vmap to simplify mapping * replace MAX_EVTCHNS macro with inline function * libxl: evtchn_l3 -> evtchn_extended The most notable bit of this series is the interface change. In order to cope with future ABIs, the interface is renamed to EVTCHNOP_register_extended. It also provides supported ABI query, so that we can remove unused ABI in the future. The semantic meaning of EVTCHNOP_register_extended changes a bit. The `level'' in parameter now changes to `cmd'', which means we should go down to specific ABI routines. ABI-specific structures are still embedded in the union. Changes since V1: * move all evtchn related macros / struct definitions to event.h * only allow 3-level evtchn for Dom0 and driver domains * add evtchn_l3 flag in libxl Diffstat: xen/arch/arm/domain.c | 1 + xen/arch/x86/domain.c | 1 + xen/arch/x86/irq.c | 7 +- xen/common/Makefile | 1 + xen/common/event_channel.c | 404 +++++++++++++++++++++++++----------- xen/common/evtchn_bitmap_abi.c | 323 ++++++++++++++++++++++++++++ xen/common/keyhandler.c | 6 +- xen/common/schedule.c | 4 +- xen/include/asm-arm/config.h | 1 + xen/include/asm-x86/config.h | 5 +- xen/include/public/event_channel.h | 48 +++++ xen/include/public/xen.h | 35 ++-- xen/include/xen/event.h | 70 ++++++- xen/include/xen/sched.h | 31 ++- 14 files changed, 779 insertions(+), 158 deletions(-)
Affected files: * event_channel.c * sched.h * event.h * xen.h Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 16 ++++++++-------- xen/include/public/xen.h | 22 +++++++++++----------- xen/include/xen/event.h | 4 ++-- xen/include/xen/sched.h | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index a0f293f..dabfa9e 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1,15 +1,15 @@ /****************************************************************************** * event_channel.c - * + * * Event notifications from VIRQs, PIRQs, and other domains. - * + * * Copyright (c) 2003-2006, K A Fraser. - * + * * 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 02111-1307 USA @@ -238,7 +238,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) lchn->u.interdomain.remote_dom = rd; lchn->u.interdomain.remote_port = (u16)rport; lchn->state = ECS_INTERDOMAIN; - + rchn->u.interdomain.remote_dom = ld; rchn->u.interdomain.remote_port = (u16)lport; rchn->state = ECS_INTERDOMAIN; @@ -255,7 +255,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) spin_unlock(&ld->event_lock); if ( ld != rd ) spin_unlock(&rd->event_lock); - + rcu_unlock_domain(rd); return rc; @@ -633,7 +633,7 @@ static void evtchn_set_pending(struct vcpu *v, int port) { vcpu_mark_events_pending(v); } - + /* Check if some VCPU might be polling for this event. */ if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) return; @@ -930,7 +930,7 @@ int evtchn_unmask(unsigned int port) /* * These operations must happen in strict order. Based on - * include/xen/event.h:evtchn_set_pending(). + * include/xen/event.h:evtchn_set_pending(). */ if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && test_bit (port, &shared_info(d, evtchn_pending)) && diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index e9431e2..ba9e1ab 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -1,8 +1,8 @@ /****************************************************************************** * xen.h - * + * * Guest OS interface to Xen. - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the @@ -137,11 +137,11 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op #endif -/* +/* * VIRTUAL INTERRUPTS - * + * * Virtual interrupts that a guest OS may receive from Xen. - * + * * In the side comments, ''V.'' denotes a per-VCPU VIRQ while ''G.'' denotes a * global VIRQ. The former can be bound once per VCPU and cannot be re-bound. * The latter can be allocated only once per guest: they must initially be @@ -190,7 +190,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); * (x) encodes the PFD as follows: * x == 0 => PFD == DOMID_SELF * x != 0 => PFD == x - 1 - * + * * Sub-commands: ptr[1:0] specifies the appropriate MMU_* command. * ------------- * ptr[1:0] == MMU_NORMAL_PT_UPDATE: @@ -236,13 +236,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); * To deallocate the pages, the operations are the reverse of the steps * mentioned above. The argument is MMUEXT_UNPIN_TABLE for all levels and the * pagetable MUST not be in use (meaning that the cr3 is not set to it). - * + * * ptr[1:0] == MMU_MACHPHYS_UPDATE: * Updates an entry in the machine->pseudo-physical mapping table. * ptr[:2] -- Machine address within the frame whose mapping to modify. * The frame must belong to the FD, if one is specified. * val -- Value to write into the mapping entry. - * + * * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD: * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed * with those in @val. @@ -588,7 +588,7 @@ typedef struct vcpu_time_info vcpu_time_info_t; struct vcpu_info { /* * ''evtchn_upcall_pending'' is written non-zero by Xen to indicate - * a pending notification for a particular VCPU. It is then cleared + * a pending notification for a particular VCPU. It is then cleared * by the guest OS /before/ checking for pending work, thus avoiding * a set-and-check race. Note that the mask is only accessed by Xen * on the CPU that is currently hosting the VCPU. This means that the @@ -646,7 +646,7 @@ struct shared_info { * 3. Virtual interrupts (''events''). A domain can bind an event-channel * port to a virtual interrupt source, such as the virtual-timer * device or the emergency console. - * + * * Event channels are addressed by a "port index". Each channel is * associated with two bits of information: * 1. PENDING -- notifies the domain that there is a pending notification @@ -657,7 +657,7 @@ struct shared_info { * becomes pending while the channel is masked then the ''edge'' is lost * (i.e., when the channel is unmasked, the guest must manually handle * pending notifications as no upcall will be scheduled by Xen). - * + * * To expedite scanning of pending notifications, any 0->1 pending * transition on an unmasked channel causes a corresponding bit in a * per-vcpu selector word to be set. Each bit in the selector covers a diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 71c3e92..65ac81a 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -1,8 +1,8 @@ /****************************************************************************** * event.h - * + * * A nice interface for passing asynchronous events to guest OSes. - * + * * Copyright (c) 2002-2006, K A Fraser */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index ccd0496..ae3cd07 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -92,7 +92,7 @@ void evtchn_destroy_final(struct domain *d); /* from complete_domain_destroy */ struct waitqueue_vcpu; -struct vcpu +struct vcpu { int vcpu_id; @@ -453,7 +453,7 @@ struct domain *domain_create( /* * rcu_lock_domain_by_id() is more efficient than get_domain_by_id(). * This is the preferred function if the returned domain reference - * is short lived, but it cannot be used if the domain reference needs + * is short lived, but it cannot be used if the domain reference needs * to be kept beyond the current scope (e.g., across a softirq). * The returned domain reference must be discarded using rcu_unlock_domain(). */ @@ -574,7 +574,7 @@ void sync_local_execstate(void); * sync_vcpu_execstate() will switch and commit @prev''s state. */ void context_switch( - struct vcpu *prev, + struct vcpu *prev, struct vcpu *next); /* -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 02/15] evtchn: reset bucket if xsm_alloc_security_evtchn fails
If xsm_alloc_security_evtchn fails, the evtchn bucket will be freed. We also need to reset pointer in bucket array to NULL. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index dabfa9e..1b702d5 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -149,6 +149,7 @@ static int get_free_port(struct domain *d) for ( j = 0; j < i; j++ ) xsm_free_security_evtchn(&chn[j]); xfree(chn); + bucket_from_port(d, port) = NULL; return -ENOMEM; } } -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 03/15] evtchn: alter internal object handling scheme
Originally, evtchn objects are stored in buckets. Now we add another layer called group. Now struct domain holds an array to evtchn groups, then each group holds pointers to a bucket. With this change, we can handle more struct evtchn in a space-efficient way. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 26 +++++++++++++++++++++++--- xen/include/xen/event.h | 12 ++++++++++-- xen/include/xen/sched.h | 12 +++++++++--- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 1b702d5..76de8ec 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -124,6 +124,7 @@ static int virq_is_global(uint32_t virq) static int get_free_port(struct domain *d) { struct evtchn *chn; + struct evtchn **grp; int port; int i, j; @@ -137,6 +138,15 @@ static int get_free_port(struct domain *d) if ( port == MAX_EVTCHNS(d) ) return -ENOSPC; + if ( unlikely(group_from_port(d, port) == NULL ) ) + { + grp = xzalloc_array(struct evtchn *, BUCKETS_PER_GROUP); + if ( unlikely(grp == NULL) ) + return -ENOMEM; + else + group_from_port(d, port) = grp; + } + chn = xzalloc_array(struct evtchn, EVTCHNS_PER_BUCKET); if ( unlikely(chn == NULL) ) return -ENOMEM; @@ -1191,7 +1201,7 @@ int evtchn_init(struct domain *d) void evtchn_destroy(struct domain *d) { - int i; + int i, j; /* After this barrier no new event-channel allocations can occur. */ BUG_ON(!d->is_dying); @@ -1206,9 +1216,19 @@ void evtchn_destroy(struct domain *d) /* Free all event-channel buckets. */ spin_lock(&d->event_lock); - for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ ) + for ( i = 0; i < NR_EVTCHN_GROUPS; i++ ) { - xsm_free_security_evtchn(d->evtchn[i]); + if ( d->evtchn[i] == NULL ) + continue; + + for ( j = 0; j < BUCKETS_PER_GROUP; j++ ) + { + if ( d->evtchn[i][j] == NULL ) + continue; + xsm_free_security_evtchn(d->evtchn[i][j]); + xfree(d->evtchn[i][j]); + d->evtchn[i][j] = NULL; + } xfree(d->evtchn[i]); d->evtchn[i] = NULL; } diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 65ac81a..ff9332a 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -69,11 +69,19 @@ int guest_enabled_event(struct vcpu *v, uint32_t virq); /* Notify remote end of a Xen-attached event channel.*/ void notify_via_xen_event_channel(struct domain *ld, int lport); -/* Internal event channel object accessors */ +/* + * Internal event channel object storage: + * Objects are organized in two level scheme: group and bucket + * A group consists of several buckets, a bucket is an array of struct evtchn + */ +#define group_from_port(d,p) \ + ((d)->evtchn[(p)/EVTCHNS_PER_GROUP]) +/* User should make sure group is not NULL */ #define bucket_from_port(d,p) \ - ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET]) + ((group_from_port(d,p))[((p)%EVTCHNS_PER_GROUP)/EVTCHNS_PER_BUCKET]) #define port_is_valid(d,p) \ (((p) >= 0) && ((p) < MAX_EVTCHNS(d)) && \ + (group_from_port(d,p) != NULL) && \ (bucket_from_port(d,p) != NULL)) #define evtchn_from_port(d,p) \ (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)]) diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index ae3cd07..7169ca0 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -51,8 +51,14 @@ extern struct domain *dom0; #define BITS_PER_EVTCHN_WORD(d) (has_32bit_shinfo(d) ? 32 : BITS_PER_XEN_ULONG) #endif #define MAX_EVTCHNS(d) (BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d)) -#define EVTCHNS_PER_BUCKET 128 -#define NR_EVTCHN_BUCKETS (NR_EVENT_CHANNELS / EVTCHNS_PER_BUCKET) +/* + * To make sure EVTCHNS_PER_BUCKET is at least 1 for 32 bit build, + * NR_EVTCHN_GROUPS * BUCKETES_PER_GROUP should be <= 1024. + */ +#define NR_EVTCHN_GROUPS 64 +#define BUCKETS_PER_GROUP 16 +#define EVTCHNS_PER_GROUP (NR_EVENT_CHANNELS / NR_EVTCHN_GROUPS) +#define EVTCHNS_PER_BUCKET (EVTCHNS_PER_GROUP / BUCKETS_PER_GROUP) struct evtchn { @@ -260,7 +266,7 @@ struct domain spinlock_t rangesets_lock; /* Event channel information. */ - struct evtchn *evtchn[NR_EVTCHN_BUCKETS]; + struct evtchn **evtchn[NR_EVTCHN_GROUPS]; spinlock_t event_lock; struct grant_table *grant_table; -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 04/15] evtchn: generalize event channel operations
Add evtchn_is_{pending,masked} and evtchn_clear_pending. Also use function pointers to refer to ABIs. This allows us to switch to alternate ABIs. 2-level ABI routines are moved to another file to separate interface and implementation. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/arch/x86/irq.c | 7 +-- xen/common/Makefile | 1 + xen/common/event_channel.c | 119 +++++++++++++++------------------------- xen/common/evtchn_bitmap_abi.c | 116 +++++++++++++++++++++++++++++++++++++++ xen/common/keyhandler.c | 6 +- xen/common/schedule.c | 2 +- xen/include/xen/event.h | 13 +++++ xen/include/xen/sched.h | 3 + 8 files changed, 184 insertions(+), 83 deletions(-) create mode 100644 xen/common/evtchn_bitmap_abi.c diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index ca829bb..4033328 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1452,7 +1452,7 @@ int pirq_guest_unmask(struct domain *d) { pirq = pirqs[i]->pirq; if ( pirqs[i]->masked && - !test_bit(pirqs[i]->evtchn, &shared_info(d, evtchn_mask)) ) + !evtchn_is_masked(d, pirqs[i]->evtchn) ) pirq_guest_eoi(pirqs[i]); } } while ( ++pirq < d->nr_pirqs && n == ARRAY_SIZE(pirqs) ); @@ -2090,13 +2090,12 @@ static void dump_irqs(unsigned char key) info = pirq_info(d, pirq); printk("%u:%3d(%c%c%c%c)", d->domain_id, pirq, - (test_bit(info->evtchn, - &shared_info(d, evtchn_pending)) ? + (evtchn_is_pending(d, info->evtchn) ? ''P'' : ''-''), (test_bit(info->evtchn / BITS_PER_EVTCHN_WORD(d), &vcpu_info(d->vcpu[0], evtchn_pending_sel)) ? ''S'' : ''-''), - (test_bit(info->evtchn, &shared_info(d, evtchn_mask)) ? + (evtchn_is_masked(d, info->evtchn) ? ''M'' : ''-''), (info->masked ? ''M'' : ''-'')); if ( i != action->nr_guests ) diff --git a/xen/common/Makefile b/xen/common/Makefile index 8a0c506..05e2160 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -6,6 +6,7 @@ obj-$(HAS_DEVICE_TREE) += device_tree.o obj-y += domctl.o obj-y += domain.o obj-y += event_channel.o +obj-y += evtchn_bitmap_abi.o obj-y += grant_table.o obj-y += irq.o obj-y += kernel.o diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 76de8ec..54ae281 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -51,6 +51,39 @@ #define consumer_is_xen(e) (!!(e)->xen_consumer) +struct evtchn_port_ops { + int (*is_pending)(struct domain *d, int port); + int (*is_masked)(struct domain *d, int port); + void (*set_pending)(struct vcpu *v, int port); + void (*clear_pending)(struct domain *d, int port); + int (*unmask)(unsigned int port); +}; + +int evtchn_is_pending(struct domain *d, int port) +{ + return d->evtchn_ops->is_pending(d, port); +} + +int evtchn_is_masked(struct domain *d, int port) +{ + return d->evtchn_ops->is_masked(d, port); +} + +void evtchn_set_pending(struct vcpu *v, int port) +{ + v->domain->evtchn_ops->set_pending(v, port); +} + +void evtchn_clear_pending(struct domain *d, int port) +{ + d->evtchn_ops->clear_pending(d, port); +} + +int evtchn_unmask(unsigned int port) +{ + return current->domain->evtchn_ops->unmask(port); +} + /* * The function alloc_unbound_xen_event_channel() allows an arbitrary * notifier function to be specified. However, very few unique functions @@ -94,8 +127,6 @@ static uint8_t get_xen_consumer(xen_event_channel_notification_t fn) /* Get the notification function for a given Xen-bound event channel. */ #define xen_notification_fn(e) (xen_consumers[(e)->xen_consumer-1]) -static void evtchn_set_pending(struct vcpu *v, int port); - static int virq_is_global(uint32_t virq) { int rc; @@ -540,7 +571,7 @@ static long __evtchn_close(struct domain *d1, int port1) } /* Clear pending event to avoid unexpected behavior on re-bind. */ - clear_bit(port1, &shared_info(d1, evtchn_pending)); + evtchn_clear_pending(d1, port1); /* Reset binding to vcpu0 when the channel is freed. */ chn1->state = ECS_FREE; @@ -623,47 +654,6 @@ out: return ret; } -static void evtchn_set_pending(struct vcpu *v, int port) -{ - struct domain *d = v->domain; - int vcpuid; - - /* - * The following bit operations must happen in strict order. - * NB. On x86, the atomic bit operations also act as memory barriers. - * There is therefore sufficiently strict ordering for this architecture -- - * others may require explicit memory barriers. - */ - - if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) - return; - - if ( !test_bit (port, &shared_info(d, evtchn_mask)) && - !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d), - &vcpu_info(v, evtchn_pending_sel)) ) - { - vcpu_mark_events_pending(v); - } - - /* Check if some VCPU might be polling for this event. */ - if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) - return; - - /* Wake any interested (or potentially interested) pollers. */ - for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); - vcpuid < d->max_vcpus; - vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) - { - v = d->vcpu[vcpuid]; - if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && - test_and_clear_bit(vcpuid, d->poll_mask) ) - { - v->poll_evtchn = 0; - vcpu_unblock(v); - } - } -} - int guest_enabled_event(struct vcpu *v, uint32_t virq) { return ((v != NULL) && (v->virq_to_evtchn[virq] != 0)); @@ -927,34 +917,6 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id) } -int evtchn_unmask(unsigned int port) -{ - struct domain *d = current->domain; - struct vcpu *v; - - ASSERT(spin_is_locked(&d->event_lock)); - - if ( unlikely(!port_is_valid(d, port)) ) - return -EINVAL; - - v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; - - /* - * These operations must happen in strict order. Based on - * include/xen/event.h:evtchn_set_pending(). - */ - if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && - test_bit (port, &shared_info(d, evtchn_pending)) && - !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), - &vcpu_info(v, evtchn_pending_sel)) ) - { - vcpu_mark_events_pending(v); - } - - return 0; -} - - static long evtchn_reset(evtchn_reset_t *r) { domid_t dom = r->dom; @@ -1180,6 +1142,13 @@ void notify_via_xen_event_channel(struct domain *ld, int lport) spin_unlock(&ld->event_lock); } +const static struct evtchn_port_ops evtchn_2l_ops = { + .is_pending = evtchn_bitmap_is_pending, + .is_masked = evtchn_bitmap_is_masked, + .set_pending = evtchn_bitmap_set_pending, + .unmask = evtchn_bitmap_unmask, + .clear_pending = evtchn_bitmap_clear_pending +}; int evtchn_init(struct domain *d) { @@ -1188,6 +1157,8 @@ int evtchn_init(struct domain *d) return -EINVAL; evtchn_from_port(d, 0)->state = ECS_RESERVED; + d->evtchn_ops = &evtchn_2l_ops; + #if MAX_VIRT_CPUS > BITS_PER_LONG d->poll_mask = xmalloc_array(unsigned long, BITS_TO_LONGS(MAX_VIRT_CPUS)); if ( !d->poll_mask ) @@ -1290,8 +1261,8 @@ static void domain_dump_evtchn_info(struct domain *d) printk(" %4u [%d/%d]: s=%d n=%d x=%d", port, - !!test_bit(port, &shared_info(d, evtchn_pending)), - !!test_bit(port, &shared_info(d, evtchn_mask)), + !!evtchn_is_pending(d, port), + !!evtchn_is_masked(d, port), chn->state, chn->notify_vcpu_id, chn->xen_consumer); switch ( chn->state ) diff --git a/xen/common/evtchn_bitmap_abi.c b/xen/common/evtchn_bitmap_abi.c new file mode 100644 index 0000000..0d747bc --- /dev/null +++ b/xen/common/evtchn_bitmap_abi.c @@ -0,0 +1,116 @@ +/****************************************************************************** + * evtchn_bitmap_abi.c + * + * Event channel 2-level ABI implementation. + * + * Copyright (c) 2013 Citrix Systems + * + * 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 02111-1307 USA + */ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/event.h> + +int evtchn_bitmap_is_pending(struct domain *d, int port) +{ + return test_bit(port, &shared_info(d, evtchn_pending)); +} + +int evtchn_bitmap_is_masked(struct domain *d, int port) +{ + return test_bit(port, &shared_info(d, evtchn_mask)); +} + +void evtchn_bitmap_set_pending(struct vcpu *v, int port) +{ + struct domain *d = v->domain; + int vcpuid; + + /* + * The following bit operations must happen in strict order. + * NB. On x86, the atomic bit operations also act as memory barriers. + * There is therefore sufficiently strict ordering for this architecture -- + * others may require explicit memory barriers. + */ + + if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) + return; + + if ( !test_bit (port, &shared_info(d, evtchn_mask)) && + !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d), + &vcpu_info(v, evtchn_pending_sel)) ) + { + vcpu_mark_events_pending(v); + } + + /* Check if some VCPU might be polling for this event. */ + if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) + return; + + /* Wake any interested (or potentially interested) pollers. */ + for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); + vcpuid < d->max_vcpus; + vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) + { + v = d->vcpu[vcpuid]; + if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && + test_and_clear_bit(vcpuid, d->poll_mask) ) + { + v->poll_evtchn = 0; + vcpu_unblock(v); + } + } +} + +void evtchn_bitmap_clear_pending(struct domain *d, int port) +{ + clear_bit(port, &shared_info(d, evtchn_pending)); +} + +int evtchn_bitmap_unmask(unsigned int port) +{ + struct domain *d = current->domain; + struct vcpu *v; + + ASSERT(spin_is_locked(&d->event_lock)); + + if ( unlikely(!port_is_valid(d, port)) ) + return -EINVAL; + + v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; + + /* + * These operations must happen in strict order. Based on + * include/xen/event.h:evtchn_set_pending(). + */ + if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && + test_bit (port, &shared_info(d, evtchn_pending)) && + !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), + &vcpu_info(v, evtchn_pending_sel)) ) + { + vcpu_mark_events_pending(v); + } + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index e9ef45f..def3bf6 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -302,10 +302,8 @@ static void dump_domains(unsigned char key) printk("Notifying guest %d:%d (virq %d, port %d, stat %d/%d/%d)\n", d->domain_id, v->vcpu_id, VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG], - test_bit(v->virq_to_evtchn[VIRQ_DEBUG], - &shared_info(d, evtchn_pending)), - test_bit(v->virq_to_evtchn[VIRQ_DEBUG], - &shared_info(d, evtchn_mask)), + evtchn_is_pending(d, v->virq_to_evtchn[VIRQ_DEBUG]), + evtchn_is_masked(d, v->virq_to_evtchn[VIRQ_DEBUG]), test_bit(v->virq_to_evtchn[VIRQ_DEBUG] / BITS_PER_EVTCHN_WORD(d), &vcpu_info(v, evtchn_pending_sel))); diff --git a/xen/common/schedule.c b/xen/common/schedule.c index de11110..6362e64 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -702,7 +702,7 @@ static long do_poll(struct sched_poll *sched_poll) goto out; rc = 0; - if ( test_bit(port, &shared_info(d, evtchn_pending)) ) + if ( evtchn_is_pending(d, port) ) goto out; } diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index ff9332a..d3ee5e0 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -54,6 +54,12 @@ int evtchn_unmask(unsigned int port); /* Move all PIRQs after a vCPU was moved to another pCPU. */ void evtchn_move_pirqs(struct vcpu *v); +/* Tell a given event-channel port is pending or not */ +int evtchn_is_pending(struct domain *d, int port); + +/* Tell a given event-channel port is masked or not */ +int evtchn_is_masked(struct domain *d, int port); + /* Allocate/free a Xen-attached event channel port. */ typedef void (*xen_event_channel_notification_t)( struct vcpu *v, unsigned int port); @@ -110,4 +116,11 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); mb(); /* set blocked status /then/ caller does his work */ \ } while ( 0 ) +/* 2-level ABI routines */ +int evtchn_bitmap_is_pending(struct domain *d, int port); +int evtchn_bitmap_is_masked(struct domain *d, int port); +void evtchn_bitmap_set_pending(struct vcpu *v, int port); +void evtchn_bitmap_clear_pending(struct domain *d, int port); +int evtchn_bitmap_unmask(unsigned int port); + #endif /* __XEN_EVENT_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 7169ca0..1cd289e 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -236,6 +236,8 @@ struct mem_event_per_domain struct mem_event_domain access; }; +struct evtchn_port_ops; + struct domain { domid_t domain_id; @@ -267,6 +269,7 @@ struct domain /* Event channel information. */ struct evtchn **evtchn[NR_EVTCHN_GROUPS]; + const struct evtchn_port_ops *evtchn_ops; spinlock_t event_lock; struct grant_table *grant_table; -- 1.7.10.4
This variable indicates the maximum number of event channels a domain can use. Also replace MAX_EVTCHNS macro with inline function which will be used to calculate max event channels in the future. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 5 +++-- xen/common/schedule.c | 2 +- xen/include/xen/event.h | 7 ++++++- xen/include/xen/sched.h | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 54ae281..ebe8278 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -166,7 +166,7 @@ static int get_free_port(struct domain *d) if ( evtchn_from_port(d, port)->state == ECS_FREE ) return port; - if ( port == MAX_EVTCHNS(d) ) + if ( port == d->max_evtchns ) return -ENOSPC; if ( unlikely(group_from_port(d, port) == NULL ) ) @@ -1153,6 +1153,7 @@ const static struct evtchn_port_ops evtchn_2l_ops = { int evtchn_init(struct domain *d) { spin_lock_init(&d->event_lock); + d->max_evtchns = max_evtchns(d); if ( get_free_port(d) != 0 ) return -EINVAL; evtchn_from_port(d, 0)->state = ECS_RESERVED; @@ -1248,7 +1249,7 @@ static void domain_dump_evtchn_info(struct domain *d) spin_lock(&d->event_lock); - for ( port = 1; port < MAX_EVTCHNS(d); ++port ) + for ( port = 1; port < d->max_evtchns; ++port ) { const struct evtchn *chn; char *ssid; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 6362e64..2e4a8d4 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -698,7 +698,7 @@ static long do_poll(struct sched_poll *sched_poll) goto out; rc = -EINVAL; - if ( port >= MAX_EVTCHNS(d) ) + if ( port >= d->max_evtchns ) goto out; rc = 0; diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index d3ee5e0..6e4d533 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -15,6 +15,11 @@ #include <asm/bitops.h> #include <asm/event.h> +static inline unsigned int max_evtchns(struct domain *d) +{ + return BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d); +} + /* * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ. * @v: VCPU to which virtual IRQ should be sent @@ -86,7 +91,7 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); #define bucket_from_port(d,p) \ ((group_from_port(d,p))[((p)%EVTCHNS_PER_GROUP)/EVTCHNS_PER_BUCKET]) #define port_is_valid(d,p) \ - (((p) >= 0) && ((p) < MAX_EVTCHNS(d)) && \ + (((p) >= 0) && ((p) < d->max_evtchns) && \ (group_from_port(d,p) != NULL) && \ (bucket_from_port(d,p) != NULL)) #define evtchn_from_port(d,p) \ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 1cd289e..f89e9c5 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -50,7 +50,6 @@ extern struct domain *dom0; #else #define BITS_PER_EVTCHN_WORD(d) (has_32bit_shinfo(d) ? 32 : BITS_PER_XEN_ULONG) #endif -#define MAX_EVTCHNS(d) (BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d)) /* * To make sure EVTCHNS_PER_BUCKET is at least 1 for 32 bit build, * NR_EVTCHN_GROUPS * BUCKETES_PER_GROUP should be <= 1024. @@ -271,6 +270,7 @@ struct domain struct evtchn **evtchn[NR_EVTCHN_GROUPS]; const struct evtchn_port_ops *evtchn_ops; spinlock_t event_lock; + unsigned int max_evtchns; struct grant_table *grant_table; -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 06/15] evtchn: implement extended event channel ABIs query
This bitmap is a 64 bits unsigned integer. Each bit represents one ABI. Bit zero is reserved. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 12 ++++++++++++ xen/include/public/event_channel.h | 14 ++++++++++++++ xen/include/xen/event.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index ebe8278..2f5f3de 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -32,6 +32,9 @@ #include <public/event_channel.h> #include <xsm/xsm.h> +/* A bitmap of supported extended event channel ABIs */ +uint64_t extended_event_channel = EVTCHN_EXTENDED_NONE; + #define ERROR_EXIT(_errno) \ do { \ gdprintk(XENLOG_WARNING, \ @@ -1051,6 +1054,15 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) break; } + case EVTCHNOP_query_extended_abis: { + struct evtchn_query_extended_abis query; + query.abis = extended_event_channel; + rc = 0; + if ( __copy_to_guest(arg, &query, 1) ) + rc = -EFAULT; + break; + } + default: rc = -ENOSYS; break; diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index 472efdb..594ea76 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -71,6 +71,7 @@ #define EVTCHNOP_bind_vcpu 8 #define EVTCHNOP_unmask 9 #define EVTCHNOP_reset 10 +#define EVTCHNOP_query_extended_abis 11 /* ` } */ typedef uint32_t evtchn_port_t; @@ -258,6 +259,19 @@ struct evtchn_reset { typedef struct evtchn_reset evtchn_reset_t; /* + * EVTCHNOP_query_extended: Query the hypervisor for supported + * extended event channel ABIs. + */ +#define EVTCHN_EXTENDED_NONE 0 +#define _EVTCHN_EXTENDED_L3 1 +#define EVTCHN_EXTENDED_L3 (1UL << _EVTCHN_EXTENDED_L3) +struct evtchn_query_extended_abis { + /* OUT parameters. */ + uint64_t abis; +}; +typedef struct evtchn_query_extended_abis evtchn_query_extended_abis_t; + +/* * ` enum neg_errnoval * ` HYPERVISOR_event_channel_op_compat(struct evtchn_op *op) * ` diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 6e4d533..0ad34fe 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -128,4 +128,6 @@ void evtchn_bitmap_set_pending(struct vcpu *v, int port); void evtchn_bitmap_clear_pending(struct domain *d, int port); int evtchn_bitmap_unmask(unsigned int port); +/* A bitmap of supported extended event channel ABIs */ +extern uint64_t extended_event_channel; #endif /* __XEN_EVENT_H__ */ -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 07/15] evtchn: define 3-level event channel registration interface
This event channel op has two sub-commands: * REGISTER_BITMAPS: register the shared pending / mask bitmaps * REGISTER_L2_SELECTOR: register L2 selector for the specific vcpu. The guest should issue REGISTER_BITMAPS first. If the registration of bitmaps succeed, it can issue REGISTER_L2_SELECTOR. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/include/public/event_channel.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index 594ea76..59a9780 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -72,6 +72,7 @@ #define EVTCHNOP_unmask 9 #define EVTCHNOP_reset 10 #define EVTCHNOP_query_extended_abis 11 +#define EVTCHNOP_register_3level 12 /* ` } */ typedef uint32_t evtchn_port_t; @@ -272,6 +273,39 @@ struct evtchn_query_extended_abis { typedef struct evtchn_query_extended_abis evtchn_query_extended_abis_t; /* + * EVTCHNOP_register_3level: Register 3-level event channel. + */ +/* + * 64 bit guests need 8 pages for evtchn_pending and evtchn_mask for + * 256k event channels while 32 bit ones only need 1 page for 32k + * event channels. + */ +#define EVTCHN_MAX_L3_PAGES 8 +/* + * A guest should register the bitmaps first, then register L2 selector for + * individual cpu. + */ +#define REGISTER_BITMAPS 1 +#define REGISTER_L2_SELECTOR 2 +struct evtchn_register_3level { + /* IN parameters. */ + uint32_t cmd; + union { + struct { + uint32_t nr_pages; + XEN_GUEST_HANDLE(xen_pfn_t) evtchn_pending; + XEN_GUEST_HANDLE(xen_pfn_t) evtchn_mask; + } bitmaps; + struct { + uint32_t cpu_id; + xen_pfn_t mfn; /* mfn of L2 selector */ + xen_pfn_t offset; /* offset of L2 selector within page */ + } l2_selector; + } u; +}; +typedef struct evtchn_register_3level evtchn_register_3level_t; + +/* * ` enum neg_errnoval * ` HYPERVISOR_event_channel_op_compat(struct evtchn_op *op) * ` -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 08/15] evtchn: add evtchn_extended in struct domain
This field is a bitmap of currently in use extended event channel ABI, which can have 0 (no extended event channel in use) or 1 bit set. It is manipulated by hypervisor only, so if anything goes wrong it is a bug. The default event channel ABI is EVTCHN_EXTENDED_NONE, which means no extended event channel is used. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 18 ++++++++++++++++-- xen/include/xen/event.h | 16 +++++++++++++++- xen/include/xen/sched.h | 1 + 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 2f5f3de..4d02fc7 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1162,6 +1162,21 @@ const static struct evtchn_port_ops evtchn_2l_ops = { .clear_pending = evtchn_bitmap_clear_pending }; +void evtchn_set_abi(struct domain *d, uint64_t abi) +{ + d->evtchn_extended = abi; + /* This must go after setting ABI */ + d->max_evtchns = max_evtchns(d); + switch ( abi ) + { + case EVTCHN_EXTENDED_NONE: + d->evtchn_ops = &evtchn_2l_ops; + break; + default: + BUG(); + } +} + int evtchn_init(struct domain *d) { spin_lock_init(&d->event_lock); @@ -1169,8 +1184,7 @@ int evtchn_init(struct domain *d) if ( get_free_port(d) != 0 ) return -EINVAL; evtchn_from_port(d, 0)->state = ECS_RESERVED; - - d->evtchn_ops = &evtchn_2l_ops; + evtchn_set_abi(d, EVTCHN_EXTENDED_NONE); #if MAX_VIRT_CPUS > BITS_PER_LONG d->poll_mask = xmalloc_array(unsigned long, BITS_TO_LONGS(MAX_VIRT_CPUS)); diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 0ad34fe..e16fdb6 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -14,10 +14,20 @@ #include <xen/softirq.h> #include <asm/bitops.h> #include <asm/event.h> +#include <public/event_channel.h> static inline unsigned int max_evtchns(struct domain *d) { - return BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d); + unsigned int ret = 0; + switch ( d->evtchn_extended ) + { + case EVTCHN_EXTENDED_NONE: + ret = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d); + break; + default: + BUG(); + } + return ret; } /* @@ -130,4 +140,8 @@ int evtchn_bitmap_unmask(unsigned int port); /* A bitmap of supported extended event channel ABIs */ extern uint64_t extended_event_channel; + +/* Set event channel ABI for a domain */ +void evtchn_set_abi(struct domain *d, uint64_t abi); + #endif /* __XEN_EVENT_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index f89e9c5..dbb7217 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -271,6 +271,7 @@ struct domain const struct evtchn_port_ops *evtchn_ops; spinlock_t event_lock; unsigned int max_evtchns; + unsigned int evtchn_extended; struct grant_table *grant_table; -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 09/15] evtchn: calculate max event channels for EVTCHN_EXTENDED_L3
Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/include/xen/event.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index e16fdb6..9531029 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -24,6 +24,10 @@ static inline unsigned int max_evtchns(struct domain *d) case EVTCHN_EXTENDED_NONE: ret = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d); break; + case EVTCHN_EXTENDED_L3: + ret = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d) + * BITS_PER_EVTCHN_WORD(d); + break; default: BUG(); } -- 1.7.10.4
Document limits of 2/3-level event channel ABIs. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/include/public/xen.h | 13 ++++++++++++- xen/include/xen/sched.h | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index ba9e1ab..e6c33d4 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -554,9 +554,20 @@ DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); /* * Event channel endpoints per domain: + * 2-level for x86: * 1024 if a long is 32 bits; 4096 if a long is 64 bits. + * 3-level for x86: + * 32k if a long is 32 bits; 256k if a long is 64 bits. + * 2-level for ARM: + * 4096 for both 32 bits and 64 bits. + * 3-level for ARM: + * 256k for both 32 bits and 64 bits. */ -#define NR_EVENT_CHANNELS (sizeof(xen_ulong_t) * sizeof(xen_ulong_t) * 64) +#define NR_EVENT_CHANNELS_L2 (sizeof(xen_ulong_t) * sizeof(xen_ulong_t) * 64) +#define NR_EVENT_CHANNELS_L3 (NR_EVENT_CHANNELS_L2 * sizeof(xen_ulong_t) * 8) +#if !defined(__XEN__) && !defined(__XEN_TOOLS__) +#define NR_EVENT_CHANNELS NR_EVENT_CHANNELS_L2 /* for compatibility */ +#endif struct vcpu_time_info { /* diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index dbb7217..6bf96bd 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -56,7 +56,7 @@ extern struct domain *dom0; */ #define NR_EVTCHN_GROUPS 64 #define BUCKETS_PER_GROUP 16 -#define EVTCHNS_PER_GROUP (NR_EVENT_CHANNELS / NR_EVTCHN_GROUPS) +#define EVTCHNS_PER_GROUP (NR_EVENT_CHANNELS_L3 / NR_EVTCHN_GROUPS) #define EVTCHNS_PER_BUCKET (EVTCHNS_PER_GROUP / BUCKETS_PER_GROUP) struct evtchn -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 11/15] evtchn: use pointers to reference evtchn_pending/mask
This allows better code sharing between 2/3-level event channel ABIs. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/arch/arm/domain.c | 1 + xen/arch/x86/domain.c | 1 + xen/common/event_channel.c | 6 ++++++ xen/common/evtchn_bitmap_abi.c | 14 +++++++------- xen/include/xen/event.h | 3 +++ xen/include/xen/sched.h | 2 ++ 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index bca3d89..f6a5560 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -471,6 +471,7 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) d->arch.vmpidr = boot_cpu_data.mpidr.bits; clear_page(d->shared_info); + evtchn_set_default_bitmap(d); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 8d30d08..d7912b3 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -547,6 +547,7 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) goto fail; clear_page(d->shared_info); + evtchn_set_default_bitmap(d); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 4d02fc7..152b77a 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1177,6 +1177,12 @@ void evtchn_set_abi(struct domain *d, uint64_t abi) } } +void evtchn_set_default_bitmap(struct domain *d) +{ + d->evtchn_pending = (xen_ulong_t *)shared_info(d, evtchn_pending); + d->evtchn_mask = (xen_ulong_t *)shared_info(d, evtchn_mask); +} + int evtchn_init(struct domain *d) { spin_lock_init(&d->event_lock); diff --git a/xen/common/evtchn_bitmap_abi.c b/xen/common/evtchn_bitmap_abi.c index 0d747bc..180a4bc 100644 --- a/xen/common/evtchn_bitmap_abi.c +++ b/xen/common/evtchn_bitmap_abi.c @@ -24,12 +24,12 @@ int evtchn_bitmap_is_pending(struct domain *d, int port) { - return test_bit(port, &shared_info(d, evtchn_pending)); + return test_bit(port, d->evtchn_pending); } int evtchn_bitmap_is_masked(struct domain *d, int port) { - return test_bit(port, &shared_info(d, evtchn_mask)); + return test_bit(port, d->evtchn_mask); } void evtchn_bitmap_set_pending(struct vcpu *v, int port) @@ -44,10 +44,10 @@ void evtchn_bitmap_set_pending(struct vcpu *v, int port) * others may require explicit memory barriers. */ - if ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) + if ( test_and_set_bit(port, d->evtchn_pending) ) return; - if ( !test_bit (port, &shared_info(d, evtchn_mask)) && + if ( !test_bit (port, d->evtchn_mask) && !test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d), &vcpu_info(v, evtchn_pending_sel)) ) { @@ -75,7 +75,7 @@ void evtchn_bitmap_set_pending(struct vcpu *v, int port) void evtchn_bitmap_clear_pending(struct domain *d, int port) { - clear_bit(port, &shared_info(d, evtchn_pending)); + clear_bit(port, d->evtchn_pending); } int evtchn_bitmap_unmask(unsigned int port) @@ -94,8 +94,8 @@ int evtchn_bitmap_unmask(unsigned int port) * These operations must happen in strict order. Based on * include/xen/event.h:evtchn_set_pending(). */ - if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && - test_bit (port, &shared_info(d, evtchn_pending)) && + if ( test_and_clear_bit(port, d->evtchn_mask) && + test_bit (port, d->evtchn_pending) && !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), &vcpu_info(v, evtchn_pending_sel)) ) { diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 9531029..2387461 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -135,6 +135,9 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); mb(); /* set blocked status /then/ caller does his work */ \ } while ( 0 ) +/* This is called after domain''s shared info page is setup */ +void evtchn_set_default_bitmap(struct domain *d); + /* 2-level ABI routines */ int evtchn_bitmap_is_pending(struct domain *d, int port); int evtchn_bitmap_is_masked(struct domain *d, int port); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 6bf96bd..71eebb6 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -270,6 +270,8 @@ struct domain struct evtchn **evtchn[NR_EVTCHN_GROUPS]; const struct evtchn_port_ops *evtchn_ops; spinlock_t event_lock; + xen_ulong_t *evtchn_pending; + xen_ulong_t *evtchn_mask; unsigned int max_evtchns; unsigned int evtchn_extended; -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 12/15] evtchn: introduce EVTCHN_WORD_BITORDER macro
This macro is used to optimise calculation. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/include/asm-arm/config.h | 1 + xen/include/asm-x86/config.h | 5 ++++- xen/include/xen/sched.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h index 8be8563..3ba7df7 100644 --- a/xen/include/asm-arm/config.h +++ b/xen/include/asm-arm/config.h @@ -24,6 +24,7 @@ /* xen_ulong_t is always 64 bits */ #define BITS_PER_XEN_ULONG 64 +#define XEN_ULONG_BITORDER 6 #define CONFIG_PAGING_ASSISTANCE 1 diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index cf93bd5..a43810d 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -8,13 +8,16 @@ #define __X86_CONFIG_H__ #define LONG_BYTEORDER 3 +#define BYTE_BITORDER 3 +#define LONG_BITORDER (BYTE_BITORDER + LONG_BYTEORDER) #define CONFIG_PAGING_LEVELS 4 #define BYTES_PER_LONG (1 << LONG_BYTEORDER) #define BITS_PER_LONG (BYTES_PER_LONG << 3) -#define BITS_PER_BYTE 8 +#define BITS_PER_BYTE (1 << BYTE_BITORDER) #define BITS_PER_XEN_ULONG BITS_PER_LONG +#define XEN_ULONG_BITORDER LONG_BITORDER #define CONFIG_X86 1 #define CONFIG_X86_HT 1 diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 71eebb6..a4d9df7 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -47,8 +47,10 @@ extern struct domain *dom0; #ifndef CONFIG_COMPAT #define BITS_PER_EVTCHN_WORD(d) BITS_PER_XEN_ULONG +#define EVTCHN_WORD_BITORDER(d) XEN_ULONG_BITORDER #else #define BITS_PER_EVTCHN_WORD(d) (has_32bit_shinfo(d) ? 32 : BITS_PER_XEN_ULONG) +#define EVTCHN_WORD_BITORDER(d) (has_32bit_shinfo(d) ? 5 : XEN_ULONG_BITORDER) #endif /* * To make sure EVTCHNS_PER_BUCKET is at least 1 for 32 bit build, -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 13/15] evtchn: infrastructure to manipulate 3-level event channel pages
Introduce evtchn_{,un}map_l3_bitmaps, evtchn_{,un}map_l2_selector for 3-level event channel ABI. Introduce evtchn_unregister_extended in teardown path. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 72 +++++++++++++++++++++ xen/common/evtchn_bitmap_abi.c | 135 ++++++++++++++++++++++++++++++++++++++++ xen/include/xen/event.h | 7 +++ xen/include/xen/sched.h | 3 + 4 files changed, 217 insertions(+) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 152b77a..d5b2e37 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -946,6 +946,53 @@ out: } +static long evtchn_register_3level(evtchn_register_3level_t *arg) +{ + struct domain *d = current->domain; + int rc; + + /* + * This domain must be in one of the two states: + * a) it has no active extended ABI in use and tries to register + * L3 bitmaps + * b) it has activated 3-level ABI and tries to register L2 + * selector + */ + if ( !((d->evtchn_extended == EVTCHN_EXTENDED_NONE && + arg->cmd == REGISTER_BITMAPS) || + (d->evtchn_extended == EVTCHN_EXTENDED_L3 && + arg->cmd == REGISTER_L2_SELECTOR)) ) + { + rc = -EINVAL; + goto out; + } + + switch ( arg->cmd ) + { + case REGISTER_BITMAPS: + rc = evtchn_map_l3_bitmaps(d, arg); + break; + case REGISTER_L2_SELECTOR: { + int vcpu_id = arg->u.l2_selector.cpu_id; + struct vcpu *v; + if ( vcpu_id >= d->max_vcpus ) + rc = -EINVAL; + else + { + v = d->vcpu[vcpu_id]; + rc = evtchn_map_l2_selector(v, arg); + } + break; + } + default: + rc = -EINVAL; + } + + out: + return rc; +} + + long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) { long rc; @@ -1063,6 +1110,14 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) break; } + case EVTCHNOP_register_3level: { + struct evtchn_register_3level reg; + if ( copy_from_guest(®, arg, 1) != 0 ) + return -EFAULT; + rc = evtchn_register_3level(®); + break; + } + default: rc = -ENOSYS; break; @@ -1202,6 +1257,21 @@ int evtchn_init(struct domain *d) return 0; } +/* Clean up all extended event channel ABI mappings */ +static void evtchn_unregister_extended(struct domain *d) +{ + switch ( d->evtchn_extended ) + { + case EVTCHN_EXTENDED_NONE: + /* Nothing to do */ + break; + case EVTCHN_EXTENDED_L3: + evtchn_unmap_all_3level(d); + break; + default: + BUG(); + } +} void evtchn_destroy(struct domain *d) { @@ -1239,6 +1309,8 @@ void evtchn_destroy(struct domain *d) spin_unlock(&d->event_lock); clear_global_virq_handlers(d); + + evtchn_unregister_extended(d); } diff --git a/xen/common/evtchn_bitmap_abi.c b/xen/common/evtchn_bitmap_abi.c index 180a4bc..e358691 100644 --- a/xen/common/evtchn_bitmap_abi.c +++ b/xen/common/evtchn_bitmap_abi.c @@ -21,6 +21,141 @@ #include <xen/errno.h> #include <xen/sched.h> #include <xen/event.h> +#include <xen/guest_access.h> + +long evtchn_map_l3_bitmaps(struct domain *d, evtchn_register_3level_t *reg) +{ + int rc; + void *pending_mapping, *mask_mapping; + xen_pfn_t evtchn_pending[EVTCHN_MAX_L3_PAGES]; + xen_pfn_t evtchn_mask[EVTCHN_MAX_L3_PAGES]; + uint32_t nr_pages; + + /* Return if we''ve mapped those bitmaps */ + if ( d->evtchn_extended == EVTCHN_EXTENDED_L3 ) + return -EBUSY; + + nr_pages = reg->u.bitmaps.nr_pages; + + if ( nr_pages > EVTCHN_MAX_L3_PAGES ) + { + rc = -EINVAL; + goto out; + } + + memset(evtchn_pending, 0, sizeof(xen_pfn_t) * EVTCHN_MAX_L3_PAGES); + memset(evtchn_mask, 0, sizeof(xen_pfn_t) * EVTCHN_MAX_L3_PAGES); + + rc = -EFAULT; /* common error code for following operations */ + if ( copy_from_guest(evtchn_pending, reg->u.bitmaps.evtchn_pending, + nr_pages) ) + goto out; + if ( copy_from_guest(evtchn_mask, reg->u.bitmaps.evtchn_mask, + nr_pages) ) + goto out; + + rc = -ENOMEM; + pending_mapping = vmap(evtchn_pending, nr_pages); + if ( !pending_mapping ) + goto out; + + + mask_mapping = vmap(evtchn_mask, nr_pages); + if ( !mask_mapping ) + { + vunmap(pending_mapping); + goto out; + } + + d->evtchn_pending = pending_mapping; + d->evtchn_mask = mask_mapping; + + evtchn_set_abi(d, EVTCHN_EXTENDED_L3); + + rc = 0; + out: + return rc; +} + +void evtchn_unmap_l3_bitmaps(struct domain *d) +{ + if ( d->evtchn_pending ) + { + vunmap(d->evtchn_pending); + d->evtchn_pending = NULL; + } + + if ( d->evtchn_mask ) + { + vunmap(d->evtchn_mask); + d->evtchn_mask = NULL; + } + + evtchn_set_abi(d, EVTCHN_EXTENDED_NONE); +} + +long evtchn_map_l2_selector(struct vcpu *v, evtchn_register_3level_t *reg) +{ + int rc; + void *mapping; + xen_pfn_t mfn = 0; + xen_pfn_t offset = 0; + + mfn = reg->u.l2_selector.mfn; + offset = reg->u.l2_selector.offset; + + /* Already mapped? */ + if ( v->evtchn_pending_sel_l2 ) + return -EBUSY; + + /* must within one page */ + if ( offset + sizeof(xen_ulong_t)*sizeof(xen_ulong_t)*8 > PAGE_SIZE ) + { + rc = -EINVAL; + goto out; + } + + mapping = vmap(&mfn, 1); + + if ( mapping == NULL ) + { + rc = -ENOMEM; + goto out; + } + + v->evtchn_pending_sel_l2 = mapping + offset; + + memcpy(&v->evtchn_pending_sel_l2[0], + &vcpu_info(v, evtchn_pending_sel), + sizeof(vcpu_info(v, evtchn_pending_sel))); + memset(&vcpu_info(v, evtchn_pending_sel), 0, + sizeof(vcpu_info(v, evtchn_pending_sel))); + set_bit(0, &vcpu_info(v, evtchn_pending_sel)); + + rc = 0; + + out: + return rc; +} + +void evtchn_unmap_l2_selector(struct vcpu *v) +{ + if ( v->evtchn_pending_sel_l2 ) + { + unsigned long addr + (unsigned long)(v->evtchn_pending_sel_l2) & PAGE_MASK; + vunmap((void *)addr); + v->evtchn_pending_sel_l2 = NULL; + } +} + +void evtchn_unmap_all_3level(struct domain *d) +{ + struct vcpu *v; + for_each_vcpu ( d, v ) + evtchn_unmap_l2_selector(v); + evtchn_unmap_l3_bitmaps(d); +} int evtchn_bitmap_is_pending(struct domain *d, int port) { diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 2387461..182546c 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -145,6 +145,13 @@ void evtchn_bitmap_set_pending(struct vcpu *v, int port); void evtchn_bitmap_clear_pending(struct domain *d, int port); int evtchn_bitmap_unmask(unsigned int port); +/* Functions used to manipulate 3-level event channel pages */ +long evtchn_map_l3_bitmaps(struct domain *d, evtchn_register_3level_t *reg); +void evtchn_unmap_l3_bitmaps(struct domain *d); +long evtchn_map_l2_selector(struct vcpu *v, evtchn_register_3level_t *reg); +void evtchn_unmap_l2_selector(struct vcpu *v); +void evtchn_unmap_all_3level(struct domain *d); + /* A bitmap of supported extended event channel ABIs */ extern uint64_t extended_event_channel; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index a4d9df7..8e330bf 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -109,6 +109,9 @@ struct vcpu struct domain *domain; + /* For 3-level event channel ABI */ + xen_ulong_t *evtchn_pending_sel_l2; + struct vcpu *next_in_list; s_time_t periodic_period; -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 14/15] evtchn: implement 3-level event channel routines
3-level event channel ABI is fully functionaly at this point, set corresponding bit in ABI bitmap as well. Also rework domain_dump_evtchn_info. Ports are processed in batches, avoid holding event_lock for too long. --- xen/common/event_channel.c | 143 +++++++++++++++++++++++++++------------- xen/common/evtchn_bitmap_abi.c | 102 +++++++++++++++++++++++----- xen/include/xen/event.h | 8 ++- 3 files changed, 192 insertions(+), 61 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index d5b2e37..0f9e8e4 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -33,7 +33,22 @@ #include <xsm/xsm.h> /* A bitmap of supported extended event channel ABIs */ -uint64_t extended_event_channel = EVTCHN_EXTENDED_NONE; +uint64_t extended_event_channel = (EVTCHN_EXTENDED_NONE | + EVTCHN_EXTENDED_L3); + +static inline const char * evtchn_abi_str(unsigned int abi) +{ + switch ( abi ) + { + case EVTCHN_EXTENDED_NONE: + return "2-level"; + case EVTCHN_EXTENDED_L3: + return "3-level"; + default: + BUG(); + } + return ""; /* make compiler happy */ +} #define ERROR_EXIT(_errno) \ do { \ @@ -1212,8 +1227,16 @@ void notify_via_xen_event_channel(struct domain *ld, int lport) const static struct evtchn_port_ops evtchn_2l_ops = { .is_pending = evtchn_bitmap_is_pending, .is_masked = evtchn_bitmap_is_masked, - .set_pending = evtchn_bitmap_set_pending, - .unmask = evtchn_bitmap_unmask, + .set_pending = evtchn_bitmap_2l_set_pending, + .unmask = evtchn_bitmap_2l_unmask, + .clear_pending = evtchn_bitmap_clear_pending +}; + +const static struct evtchn_port_ops evtchn_3l_ops = { + .is_pending = evtchn_bitmap_is_pending, + .is_masked = evtchn_bitmap_is_masked, + .set_pending = evtchn_bitmap_3l_set_pending, + .unmask = evtchn_bitmap_3l_unmask, .clear_pending = evtchn_bitmap_clear_pending }; @@ -1227,6 +1250,9 @@ void evtchn_set_abi(struct domain *d, uint64_t abi) case EVTCHN_EXTENDED_NONE: d->evtchn_ops = &evtchn_2l_ops; break; + case EVTCHN_EXTENDED_L3: + d->evtchn_ops = &evtchn_3l_ops; + break; default: BUG(); } @@ -1344,61 +1370,90 @@ static void domain_dump_evtchn_info(struct domain *d) { unsigned int port; int irq; + int i, j, k; bitmap_scnlistprintf(keyhandler_scratch, sizeof(keyhandler_scratch), d->poll_mask, d->max_vcpus); printk("Event channel information for domain %d:\n" + "Using %s event channel ABI\n" "Polling vCPUs: {%s}\n" - " port [p/m]\n", d->domain_id, keyhandler_scratch); + " port [p/m]\n", + d->domain_id, evtchn_abi_str(d->evtchn_extended), + keyhandler_scratch); - spin_lock(&d->event_lock); - - for ( port = 1; port < d->max_evtchns; ++port ) + /* + * Print out infomation on per-group basis, avoid holding + * event_lock for too long. It''s worth noting that groups and + * buckets never shrink unless domain is being destroyed. + */ + for ( i = 0; i < NR_EVTCHN_GROUPS; i++ ) { - const struct evtchn *chn; - char *ssid; - - if ( !port_is_valid(d, port) ) - continue; - chn = evtchn_from_port(d, port); - if ( chn->state == ECS_FREE ) - continue; + if ( unlikely(d->is_dying) ) + break; - printk(" %4u [%d/%d]: s=%d n=%d x=%d", - port, - !!evtchn_is_pending(d, port), - !!evtchn_is_masked(d, port), - chn->state, chn->notify_vcpu_id, chn->xen_consumer); + spin_lock(&d->event_lock); - switch ( chn->state ) + if ( d->evtchn[i] == NULL ) { - case ECS_UNBOUND: - printk(" d=%d", chn->u.unbound.remote_domid); - break; - case ECS_INTERDOMAIN: - printk(" d=%d p=%d", - chn->u.interdomain.remote_dom->domain_id, - chn->u.interdomain.remote_port); - break; - case ECS_PIRQ: - irq = domain_pirq_to_irq(d, chn->u.pirq.irq); - printk(" p=%d i=%d", chn->u.pirq.irq, irq); - break; - case ECS_VIRQ: - printk(" v=%d", chn->u.virq); - break; + spin_unlock(&d->event_lock); + continue; } - ssid = xsm_show_security_evtchn(d, chn); - if (ssid) { - printk(" Z=%s\n", ssid); - xfree(ssid); - } else { - printk("\n"); + for ( j = 0; j < BUCKETS_PER_GROUP; j++ ) + { + if ( d->evtchn[i][j] == NULL ) + continue; + + for ( k = 0; k < EVTCHNS_PER_BUCKET; k++ ) + { + const struct evtchn *chn; + char *ssid; + + port = i * EVTCHNS_PER_GROUP + j * EVTCHNS_PER_BUCKET + k; + + if ( !port_is_valid(d, port) ) + continue; + chn = evtchn_from_port(d, port); + if ( chn->state == ECS_FREE ) + continue; + + printk(" %4u [%d/%d]: s=%d n=%d x=%d", + port, + !!evtchn_is_pending(d, port), + !!evtchn_is_masked(d, port), + chn->state, chn->notify_vcpu_id, chn->xen_consumer); + + switch ( chn->state ) + { + case ECS_UNBOUND: + printk(" d=%d", chn->u.unbound.remote_domid); + break; + case ECS_INTERDOMAIN: + printk(" d=%d p=%d", + chn->u.interdomain.remote_dom->domain_id, + chn->u.interdomain.remote_port); + break; + case ECS_PIRQ: + irq = domain_pirq_to_irq(d, chn->u.pirq.irq); + printk(" p=%d i=%d", chn->u.pirq.irq, irq); + break; + case ECS_VIRQ: + printk(" v=%d", chn->u.virq); + break; + } + + ssid = xsm_show_security_evtchn(d, chn); + if (ssid) + { + printk(" Z=%s\n", ssid); + xfree(ssid); + } else { + printk("\n"); + } + } } + spin_unlock(&d->event_lock); } - - spin_unlock(&d->event_lock); } static void dump_evtchn_info(unsigned char key) diff --git a/xen/common/evtchn_bitmap_abi.c b/xen/common/evtchn_bitmap_abi.c index e358691..5110613 100644 --- a/xen/common/evtchn_bitmap_abi.c +++ b/xen/common/evtchn_bitmap_abi.c @@ -1,7 +1,7 @@ /****************************************************************************** * evtchn_bitmap_abi.c * - * Event channel 2-level ABI implementation. + * Event channel 2/3-level ABI implementation. * * Copyright (c) 2013 Citrix Systems * @@ -167,10 +167,33 @@ int evtchn_bitmap_is_masked(struct domain *d, int port) return test_bit(port, d->evtchn_mask); } -void evtchn_bitmap_set_pending(struct vcpu *v, int port) +static void __check_vcpu_polling(struct vcpu *v, int port) { - struct domain *d = v->domain; int vcpuid; + struct domain *d = v->domain; + + /* Check if some VCPU might be polling for this event. */ + if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) + return; + + /* Wake any interested (or potentially interested) pollers. */ + for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); + vcpuid < d->max_vcpus; + vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) + { + v = d->vcpu[vcpuid]; + if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && + test_and_clear_bit(vcpuid, d->poll_mask) ) + { + v->poll_evtchn = 0; + vcpu_unblock(v); + } + } +} + +void evtchn_bitmap_2l_set_pending(struct vcpu *v, int port) +{ + struct domain *d = v->domain; /* * The following bit operations must happen in strict order. @@ -193,19 +216,36 @@ void evtchn_bitmap_set_pending(struct vcpu *v, int port) if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) ) return; - /* Wake any interested (or potentially interested) pollers. */ - for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus); - vcpuid < d->max_vcpus; - vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) ) + __check_vcpu_polling(v, port); +} + +void evtchn_bitmap_3l_set_pending(struct vcpu *v, int port) +{ + struct domain *d = v->domain; + unsigned int l1bit = port >> (EVTCHN_WORD_BITORDER(d) << 1); + unsigned int l2bit = port >> EVTCHN_WORD_BITORDER(d); + + if (unlikely(!v->evtchn_pending_sel_l2)) + return; + + /* + * The following bit operations must happen in strict order. + * NB. On x86, the atomic bit operations also act as memory barriers. + * There is therefore sufficiently strict ordering for this architecture -- + * others may require explicit memory barriers. + */ + + if ( test_and_set_bit(port, d->evtchn_pending) ) + return; + + if ( !test_bit(port, d->evtchn_mask) && + !test_and_set_bit(l2bit, v->evtchn_pending_sel_l2) && + !test_and_set_bit(l1bit, &vcpu_info(v, evtchn_pending_sel)) ) { - v = d->vcpu[vcpuid]; - if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) && - test_and_clear_bit(vcpuid, d->poll_mask) ) - { - v->poll_evtchn = 0; - vcpu_unblock(v); - } + vcpu_mark_events_pending(v); } + + __check_vcpu_polling(v, port); } void evtchn_bitmap_clear_pending(struct domain *d, int port) @@ -213,7 +253,7 @@ void evtchn_bitmap_clear_pending(struct domain *d, int port) clear_bit(port, d->evtchn_pending); } -int evtchn_bitmap_unmask(unsigned int port) +int evtchn_bitmap_2l_unmask(unsigned int port) { struct domain *d = current->domain; struct vcpu *v; @@ -240,6 +280,38 @@ int evtchn_bitmap_unmask(unsigned int port) return 0; } +int evtchn_bitmap_3l_unmask(unsigned int port) +{ + struct domain *d = current->domain; + struct vcpu *v; + unsigned int l1bit = port >> (EVTCHN_WORD_BITORDER(d) << 1); + unsigned int l2bit = port >> EVTCHN_WORD_BITORDER(d); + + ASSERT(spin_is_locked(&d->event_lock)); + + if ( unlikely(!port_is_valid(d, port)) ) + return -EINVAL; + + v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; + + if (unlikely(!v->evtchn_pending_sel_l2)) + return -EINVAL; + + /* + * These operations must happen in strict order. Based on + * include/xen/event.h:evtchn_set_pending(). + */ + if ( test_and_clear_bit(port, d->evtchn_mask) && + test_bit (port, d->evtchn_pending) && + !test_and_set_bit (l2bit, v->evtchn_pending_sel_l2) && + !test_and_set_bit (l1bit, &vcpu_info(v, evtchn_pending_sel)) ) + { + vcpu_mark_events_pending(v); + } + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index 182546c..3f7a18f 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -139,11 +139,15 @@ void notify_via_xen_event_channel(struct domain *ld, int lport); void evtchn_set_default_bitmap(struct domain *d); /* 2-level ABI routines */ +void evtchn_bitmap_2l_set_pending(struct vcpu *v, int port); +int evtchn_bitmap_2l_unmask(unsigned int port); +/* 3-level ABI routines */ +void evtchn_bitmap_3l_set_pending(struct vcpu *v, int port); +int evtchn_bitmap_3l_unmask(unsigned int port); +/* Shared routines for 2/3-level ABIs */ int evtchn_bitmap_is_pending(struct domain *d, int port); int evtchn_bitmap_is_masked(struct domain *d, int port); -void evtchn_bitmap_set_pending(struct vcpu *v, int port); void evtchn_bitmap_clear_pending(struct domain *d, int port); -int evtchn_bitmap_unmask(unsigned int port); /* Functions used to manipulate 3-level event channel pages */ long evtchn_map_l3_bitmaps(struct domain *d, evtchn_register_3level_t *reg); -- 1.7.10.4
Wei Liu
2013-Mar-19 15:15 UTC
[RFC PATCH V5 15/15] evtchn: only allow 3-level event channel on Dom0
Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- xen/common/event_channel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 0f9e8e4..f48c3a2 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1118,7 +1118,10 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) case EVTCHNOP_query_extended_abis: { struct evtchn_query_extended_abis query; + struct domain *d = current->domain; query.abis = extended_event_channel; + if ( d->domain_id != 0 ) + query.abis &= ~EVTCHN_EXTENDED_L3; rc = 0; if ( __copy_to_guest(arg, &query, 1) ) rc = -EFAULT; @@ -1127,6 +1130,9 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) case EVTCHNOP_register_3level: { struct evtchn_register_3level reg; + struct domain *d = current->domain; + if ( d->domain_id != 0 ) + return -EPERM; if ( copy_from_guest(®, arg, 1) != 0 ) return -EFAULT; rc = evtchn_register_3level(®); -- 1.7.10.4
Jan Beulich
2013-Mar-20 09:22 UTC
Re: [RFC PATCH V5 03/15] evtchn: alter internal object handling scheme
>>> On 19.03.13 at 16:15, Wei Liu <wei.liu2@citrix.com> wrote: > @@ -137,6 +138,15 @@ static int get_free_port(struct domain *d) > if ( port == MAX_EVTCHNS(d) ) > return -ENOSPC; > > + if ( unlikely(group_from_port(d, port) == NULL ) ) > + { > + grp = xzalloc_array(struct evtchn *, BUCKETS_PER_GROUP); > + if ( unlikely(grp == NULL) ) > + return -ENOMEM; > + elseNo need for the "else" here.> + group_from_port(d, port) = grp; > + } > + > chn = xzalloc_array(struct evtchn, EVTCHNS_PER_BUCKET); > if ( unlikely(chn == NULL) ) > return -ENOMEM; > @@ -1191,7 +1201,7 @@ int evtchn_init(struct domain *d) > > void evtchn_destroy(struct domain *d) > { > - int i; > + int i, j;If you touch places like this, converting to "unsigned int" would be appreciated. Jan
Jan Beulich
2013-Mar-20 09:31 UTC
Re: [RFC PATCH V5 04/15] evtchn: generalize event channel operations
>>> On 19.03.13 at 16:15, Wei Liu <wei.liu2@citrix.com> wrote: > @@ -1180,6 +1142,13 @@ void notify_via_xen_event_channel(struct domain *ld, int lport) > spin_unlock(&ld->event_lock); > } > > +const static struct evtchn_port_ops evtchn_2l_ops = {Even if the language permits this, "const" preceding "static" looks a bit odd (and is inconsistent with all other code, with one exception in the arinc653 scheduler). Jan> + .is_pending = evtchn_bitmap_is_pending, > + .is_masked = evtchn_bitmap_is_masked, > + .set_pending = evtchn_bitmap_set_pending, > + .unmask = evtchn_bitmap_unmask, > + .clear_pending = evtchn_bitmap_clear_pending > +}; > > int evtchn_init(struct domain *d) > {