diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-04-05 19:30:02 +0100 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-04-05 19:30:02 +0100 |
commit | 6f1d9ff91969db563dad7f8e703b88eda7ee2c8e (patch) | |
tree | 996e86277e291f2a30c124509202f707bd88ff28 | |
parent | b0a4d66a6cf065ab0a4341ba88cc75dccfbe1141 (diff) | |
download | xen-6f1d9ff91969db563dad7f8e703b88eda7ee2c8e.tar.gz xen-6f1d9ff91969db563dad7f8e703b88eda7ee2c8e.tar.bz2 xen-6f1d9ff91969db563dad7f8e703b88eda7ee2c8e.zip |
Backtrack on the new interface for reserved event-channel
ports, as binding them in user space via the evtchn driver
would be a pain. Instead extend VIRQs so they can be
classified as 'global' or 'per vcpu'. The former can only
be allocated once per guest, but can be re-bound to
an arbitrary VCPU.
Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r-- | xen/arch/ia64/xen/xentime.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/time.c | 2 | ||||
-rw-r--r-- | xen/common/domain.c | 8 | ||||
-rw-r--r-- | xen/common/event_channel.c | 101 | ||||
-rw-r--r-- | xen/common/keyhandler.c | 2 | ||||
-rw-r--r-- | xen/drivers/char/console.c | 2 | ||||
-rw-r--r-- | xen/include/public/event_channel.h | 18 | ||||
-rw-r--r-- | xen/include/public/xen.h | 15 | ||||
-rw-r--r-- | xen/include/xen/event.h | 18 |
9 files changed, 100 insertions, 68 deletions
diff --git a/xen/arch/ia64/xen/xentime.c b/xen/arch/ia64/xen/xentime.c index 97a615440d..50d8dbf466 100644 --- a/xen/arch/ia64/xen/xentime.c +++ b/xen/arch/ia64/xen/xentime.c @@ -274,6 +274,6 @@ int reprogram_timer(s_time_t timeout) void send_timer_event(struct vcpu *v) { - send_guest_virq(v, VIRQ_TIMER); + send_guest_vcpu_virq(v, VIRQ_TIMER); } diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index ef4c7901bd..85f52f4d75 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -916,7 +916,7 @@ void __init early_time_init(void) void send_timer_event(struct vcpu *v) { - send_guest_virq(v, VIRQ_TIMER); + send_guest_vcpu_virq(v, VIRQ_TIMER); } /* diff --git a/xen/common/domain.c b/xen/common/domain.c index b582719545..3637d4c45c 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -137,7 +137,7 @@ void domain_kill(struct domain *d) domain_relinquish_resources(d); put_domain(d); - send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC); + send_guest_global_virq(dom0, VIRQ_DOM_EXC); } } @@ -192,7 +192,7 @@ static void domain_shutdown_finalise(void) /* Don't set DOMF_shutdown until execution contexts are sync'ed. */ if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) ) - send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC); + send_guest_global_virq(dom0, VIRQ_DOM_EXC); UNLOCK_BIGLOCK(d); @@ -267,7 +267,7 @@ void domain_pause_for_debugger(void) for_each_vcpu ( d, v ) vcpu_sleep_nosync(v); - send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER); + send_guest_global_virq(dom0, VIRQ_DEBUGGER); } @@ -307,7 +307,7 @@ void domain_destroy(struct domain *d) free_domain(d); - send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC); + send_guest_global_virq(dom0, VIRQ_DOM_EXC); } void vcpu_pause(struct vcpu *v) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 2f766f7d31..ccb96b0f65 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -3,7 +3,7 @@ * * Event notifications from VIRQs, PIRQs, and other domains. * - * Copyright (c) 2003-2005, K A Fraser. + * 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 @@ -47,6 +47,27 @@ } while ( 0 ) +static int virq_is_global(int virq) +{ + int rc; + + ASSERT((virq >= 0) && (virq < NR_VIRQS)); + + switch ( virq ) + { + case VIRQ_TIMER: + case VIRQ_DEBUG: + rc = 0; + break; + default: + rc = 1; + break; + } + + return rc; +} + + static int get_free_port(struct domain *d) { struct evtchn *chn; @@ -182,6 +203,9 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind) if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) ) return -EINVAL; + if ( virq_is_global(virq) && (vcpu != 0) ) + return -EINVAL; + if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) ) return -ENOENT; @@ -474,19 +498,43 @@ void evtchn_set_pending(struct vcpu *v, int port) } -void send_guest_virq(struct vcpu *v, int virq) +void send_guest_vcpu_virq(struct vcpu *v, int virq) +{ + int port; + + ASSERT(!virq_is_global(virq)); + + port = v->virq_to_evtchn[virq]; + if ( unlikely(port == 0) ) + return; + + evtchn_set_pending(v, port); +} + +void send_guest_global_virq(struct domain *d, int virq) { - int port = v->virq_to_evtchn[virq]; + int port; + struct evtchn *chn; + + ASSERT(virq_is_global(virq)); - if ( likely(port != 0) ) - evtchn_set_pending(v, port); + port = d->vcpu[0]->virq_to_evtchn[virq]; + if ( unlikely(port == 0) ) + return; + + chn = evtchn_from_port(d, port); + evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port); } void send_guest_pirq(struct domain *d, int pirq) { int port = d->pirq_to_evtchn[pirq]; - struct evtchn *chn = evtchn_from_port(d, port); + struct evtchn *chn; + + ASSERT(port != 0); + + chn = evtchn_from_port(d, port); evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port); } @@ -576,6 +624,12 @@ long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id) chn = evtchn_from_port(d, port); switch ( chn->state ) { + case ECS_VIRQ: + if ( virq_is_global(chn->u.virq) ) + chn->notify_vcpu_id = vcpu_id; + else + rc = -EINVAL; + break; case ECS_UNBOUND: case ECS_INTERDOMAIN: case ECS_PIRQ: @@ -702,41 +756,6 @@ long do_event_channel_op(GUEST_HANDLE(evtchn_op_t) uop) } -int evtchn_open_reserved_port(struct domain *d) -{ - struct evtchn *chn; - int port; - - spin_lock(&d->evtchn_lock); - - if ( (port = get_free_port(d)) >= 0 ) - { - chn = evtchn_from_port(d, port); - chn->state = ECS_RESERVED; - } - - spin_unlock(&d->evtchn_lock); - - return port; -} - - -void evtchn_close_reserved_port(struct domain *d, int port) -{ - struct evtchn *chn; - - spin_lock(&d->evtchn_lock); - - BUG_ON(!port_is_valid(d, port)); - - chn = evtchn_from_port(d, port); - chn->state = ECS_FREE; - chn->notify_vcpu_id = 0; - - spin_unlock(&d->evtchn_lock); -} - - void evtchn_notify_reserved_port(struct domain *d, int port) { struct evtchn *chn = evtchn_from_port(d, port); diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index d1a87ac2c3..f881412ec7 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -162,7 +162,7 @@ static void dump_domains(unsigned char key) &d->shared_info->evtchn_mask[0]), test_bit(v->virq_to_evtchn[VIRQ_DEBUG]/BITS_PER_LONG, &v->vcpu_info->evtchn_pending_sel)); - send_guest_virq(v, VIRQ_DEBUG); + send_guest_vcpu_virq(v, VIRQ_DEBUG); } } diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 2755f5e46b..df4706bcb2 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -294,7 +294,7 @@ static void __serial_rx(char c, struct cpu_user_regs *regs) if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE ) serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c; /* Always notify the guest: prevents receive path from getting stuck. */ - send_guest_virq(dom0->vcpu[0], VIRQ_CONSOLE); + send_guest_global_virq(dom0, VIRQ_CONSOLE); } static void serial_rx(char c, struct cpu_user_regs *regs) diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index c556163034..f1e067b4a3 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -50,9 +50,13 @@ typedef struct evtchn_bind_interdomain { * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified * vcpu. * NOTES: - * 1. A virtual IRQ may be bound to at most one event channel per vcpu. - * 2. The allocated event channel is bound to the specified vcpu. The binding - * may not be changed. + * 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list + * in xen.h for the classification of each VIRQ. + * 2. Global VIRQs must be allocated on VCPU0 but can subsequently be + * re-bound via EVTCHNOP_bind_vcpu. + * 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu. + * The allocated event channel is bound to the specified vcpu and the + * binding cannot be changed. */ #define EVTCHNOP_bind_virq 1 typedef struct evtchn_bind_virq { @@ -152,9 +156,11 @@ typedef struct evtchn_status { * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an * event is pending. * NOTES: - * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised - * the binding. This binding cannot be changed. - * 2. All other channels notify vcpu0 by default. This default is set when + * 1. IPI-bound channels always notify the vcpu specified at bind time. + * This binding cannot be changed. + * 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time. + * This binding cannot be changed. + * 3. All other channels notify vcpu0 by default. This default is set when * the channel is allocated (a port that is freed and subsequently reused * has its binding reset to vcpu0). */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 2921a140cd..1da6ede005 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -65,12 +65,17 @@ * 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 + * allocated to VCPU0 but can subsequently be re-bound. */ -#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */ -#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */ -#define VIRQ_CONSOLE 2 /* (DOM0) Bytes received on emergency console. */ -#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */ -#define VIRQ_DEBUGGER 6 /* (DOM0) A domain has paused for debugging. */ +#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */ +#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */ +#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */ +#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */ +#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */ #define NR_VIRQS 8 /* diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index e56b991406..13b2b5f9be 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -3,7 +3,7 @@ * * A nice interface for passing asynchronous events to guest OSes. * - * Copyright (c) 2002-2005, K A Fraser + * Copyright (c) 2002-2006, K A Fraser */ #ifndef __XEN_EVENT_H__ @@ -18,11 +18,18 @@ extern void evtchn_set_pending(struct vcpu *v, int port); /* - * send_guest_virq: + * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ. * @v: VCPU to which virtual IRQ should be sent * @virq: Virtual IRQ number (VIRQ_*) */ -extern void send_guest_virq(struct vcpu *v, int virq); +extern void send_guest_vcpu_virq(struct vcpu *v, int virq); + +/* + * send_guest_global_virq: Notify guest via a global VIRQ. + * @d: Domain to which virtual IRQ should be sent + * @virq: Virtual IRQ number (VIRQ_*) + */ +extern void send_guest_global_virq(struct domain *d, int virq); /* * send_guest_pirq: @@ -45,9 +52,4 @@ extern long evtchn_send(unsigned int lport); /* Bind a local event-channel port to the specified VCPU. */ extern long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); -/* Reserved event-channel ports for other Xen subsystems. */ -int evtchn_open_reserved_port(struct domain *d); -void evtchn_close_reserved_port(struct domain *d, int port); -void evtchn_notify_reserved_port(struct domain *d, int port); - #endif /* __XEN_EVENT_H__ */ |