diff options
author | Daniel De Graaf <dgdegra@tycho.nsa.gov> | 2012-01-28 13:48:03 +0000 |
---|---|---|
committer | Daniel De Graaf <dgdegra@tycho.nsa.gov> | 2012-01-28 13:48:03 +0000 |
commit | 87521589aa6a677bad2b4a80b8fd3ad152c1c274 (patch) | |
tree | 86d58beaeede99086666d61c3d1aff63ee800ee5 /xen/common/event_channel.c | |
parent | 14eb3b41d03f75b89928fad8f720f7d49598b0be (diff) | |
download | xen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.tar.gz xen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.tar.bz2 xen-87521589aa6a677bad2b4a80b8fd3ad152c1c274.zip |
xen: allow global VIRQ handlers to be delegated to other domains
This patch sends global VIRQs to a domain designated as the VIRQ
handler
instead of sending all global VIRQ events to dom0. This is required in
order to run xenstored in a stubdom, because VIRQ_DOM_EXC must be sent
to xenstored for domain destruction to work properly.
This patch was inspired by the xenstored stubdomain patch series sent
to xen-devel by Alex Zeffertt in 2009.
Signed-off-by: Diego Ongaro <diego.ongaro@citrix.com>
Signed-off-by: Alex Zeffertt <alex.zeffertt@eu.citrix.com>
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/common/event_channel.c')
-rw-r--r-- | xen/common/event_channel.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 921204237d..43bd16755e 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -689,7 +689,7 @@ void send_guest_vcpu_virq(struct vcpu *v, int virq) spin_unlock_irqrestore(&v->virq_lock, flags); } -void send_guest_global_virq(struct domain *d, int virq) +static void send_guest_global_virq(struct domain *d, int virq) { unsigned long flags; int port; @@ -739,6 +739,68 @@ int send_guest_pirq(struct domain *d, const struct pirq *pirq) return evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port); } +static struct domain *global_virq_handlers[NR_VIRQS] __read_mostly; + +static DEFINE_SPINLOCK(global_virq_handlers_lock); + +void send_global_virq(uint32_t virq) +{ + ASSERT(virq < NR_VIRQS); + ASSERT(virq_is_global(virq)); + + send_guest_global_virq(global_virq_handlers[virq] ?: dom0, virq); +} + +int set_global_virq_handler(struct domain *d, uint32_t virq) +{ + struct domain *old; + + if (virq >= NR_VIRQS) + return -EINVAL; + if (!virq_is_global(virq)) + return -EINVAL; + + if (global_virq_handlers[virq] == d) + return 0; + + if (unlikely(!get_domain(d))) + return -EINVAL; + + spin_lock(&global_virq_handlers_lock); + old = global_virq_handlers[virq]; + global_virq_handlers[virq] = d; + spin_unlock(&global_virq_handlers_lock); + + if (old != NULL) + put_domain(old); + + return 0; +} + +static void clear_global_virq_handlers(struct domain *d) +{ + uint32_t virq; + int put_count = 0; + + spin_lock(&global_virq_handlers_lock); + + for (virq = 0; virq < NR_VIRQS; virq++) + { + if (global_virq_handlers[virq] == d) + { + global_virq_handlers[virq] = NULL; + put_count++; + } + } + + spin_unlock(&global_virq_handlers_lock); + + while (put_count) + { + put_domain(d); + put_count--; + } +} static long evtchn_status(evtchn_status_t *status) { @@ -1160,6 +1222,8 @@ void evtchn_destroy(struct domain *d) d->evtchn[i] = NULL; } spin_unlock(&d->event_lock); + + clear_global_virq_handlers(d); } |