ia64/xen-unstable

view xen/common/event_channel.c @ 9597:8f7aad20b4a5

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>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 05 19:30:02 2006 +0100 (2006-04-05)
parents e1152d55ea31
children 050ad9813cdb
line source
1 /******************************************************************************
2 * event_channel.c
3 *
4 * Event notifications from VIRQs, PIRQs, and other domains.
5 *
6 * Copyright (c) 2003-2006, K A Fraser.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
18 #include <xen/config.h>
19 #include <xen/init.h>
20 #include <xen/lib.h>
21 #include <xen/errno.h>
22 #include <xen/sched.h>
23 #include <xen/event.h>
24 #include <xen/irq.h>
25 #include <xen/iocap.h>
26 #include <xen/guest_access.h>
27 #include <asm/current.h>
29 #include <public/xen.h>
30 #include <public/event_channel.h>
31 #include <acm/acm_hooks.h>
33 #define bucket_from_port(d,p) \
34 ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
35 #define port_is_valid(d,p) \
36 (((p) >= 0) && ((p) < MAX_EVTCHNS) && \
37 (bucket_from_port(d,p) != NULL))
38 #define evtchn_from_port(d,p) \
39 (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
41 #define ERROR_EXIT(_errno) \
42 do { \
43 DPRINTK("EVTCHNOP failure: domain %d, error %d, line %d\n", \
44 current->domain->domain_id, (_errno), __LINE__); \
45 rc = (_errno); \
46 goto out; \
47 } while ( 0 )
50 static int virq_is_global(int virq)
51 {
52 int rc;
54 ASSERT((virq >= 0) && (virq < NR_VIRQS));
56 switch ( virq )
57 {
58 case VIRQ_TIMER:
59 case VIRQ_DEBUG:
60 rc = 0;
61 break;
62 default:
63 rc = 1;
64 break;
65 }
67 return rc;
68 }
71 static int get_free_port(struct domain *d)
72 {
73 struct evtchn *chn;
74 int port;
76 for ( port = 0; port_is_valid(d, port); port++ )
77 if ( evtchn_from_port(d, port)->state == ECS_FREE )
78 return port;
80 if ( port == MAX_EVTCHNS )
81 return -ENOSPC;
83 chn = xmalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
84 if ( unlikely(chn == NULL) )
85 return -ENOMEM;
86 memset(chn, 0, EVTCHNS_PER_BUCKET * sizeof(*chn));
87 bucket_from_port(d, port) = chn;
89 return port;
90 }
93 static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
94 {
95 struct evtchn *chn;
96 struct domain *d;
97 int port;
98 domid_t dom = alloc->dom;
99 long rc = 0;
101 if ( dom == DOMID_SELF )
102 dom = current->domain->domain_id;
103 else if ( !IS_PRIV(current->domain) )
104 return -EPERM;
106 if ( (d = find_domain_by_id(dom)) == NULL )
107 return -ESRCH;
109 spin_lock(&d->evtchn_lock);
111 if ( (port = get_free_port(d)) < 0 )
112 ERROR_EXIT(port);
113 chn = evtchn_from_port(d, port);
115 chn->state = ECS_UNBOUND;
116 if ( (chn->u.unbound.remote_domid = alloc->remote_dom) == DOMID_SELF )
117 chn->u.unbound.remote_domid = current->domain->domain_id;
119 alloc->port = port;
121 out:
122 spin_unlock(&d->evtchn_lock);
124 put_domain(d);
126 return rc;
127 }
130 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
131 {
132 struct evtchn *lchn, *rchn;
133 struct domain *ld = current->domain, *rd;
134 int lport, rport = bind->remote_port;
135 domid_t rdom = bind->remote_dom;
136 long rc = 0;
138 if ( rdom == DOMID_SELF )
139 rdom = current->domain->domain_id;
141 if ( (rd = find_domain_by_id(rdom)) == NULL )
142 return -ESRCH;
144 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
145 if ( ld < rd )
146 {
147 spin_lock(&ld->evtchn_lock);
148 spin_lock(&rd->evtchn_lock);
149 }
150 else
151 {
152 if ( ld != rd )
153 spin_lock(&rd->evtchn_lock);
154 spin_lock(&ld->evtchn_lock);
155 }
157 if ( (lport = get_free_port(ld)) < 0 )
158 ERROR_EXIT(lport);
159 lchn = evtchn_from_port(ld, lport);
161 if ( !port_is_valid(rd, rport) )
162 ERROR_EXIT(-EINVAL);
163 rchn = evtchn_from_port(rd, rport);
164 if ( (rchn->state != ECS_UNBOUND) ||
165 (rchn->u.unbound.remote_domid != ld->domain_id) )
166 ERROR_EXIT(-EINVAL);
168 lchn->u.interdomain.remote_dom = rd;
169 lchn->u.interdomain.remote_port = (u16)rport;
170 lchn->state = ECS_INTERDOMAIN;
172 rchn->u.interdomain.remote_dom = ld;
173 rchn->u.interdomain.remote_port = (u16)lport;
174 rchn->state = ECS_INTERDOMAIN;
176 /*
177 * We may have lost notifications on the remote unbound port. Fix that up
178 * here by conservatively always setting a notification on the local port.
179 */
180 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
182 bind->local_port = lport;
184 out:
185 spin_unlock(&ld->evtchn_lock);
186 if ( ld != rd )
187 spin_unlock(&rd->evtchn_lock);
189 put_domain(rd);
191 return rc;
192 }
195 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
196 {
197 struct evtchn *chn;
198 struct vcpu *v;
199 struct domain *d = current->domain;
200 int port, virq = bind->virq, vcpu = bind->vcpu;
201 long rc = 0;
203 if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
204 return -EINVAL;
206 if ( virq_is_global(virq) && (vcpu != 0) )
207 return -EINVAL;
209 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
210 return -ENOENT;
212 spin_lock(&d->evtchn_lock);
214 if ( v->virq_to_evtchn[virq] != 0 )
215 ERROR_EXIT(-EEXIST);
217 if ( (port = get_free_port(d)) < 0 )
218 ERROR_EXIT(port);
220 chn = evtchn_from_port(d, port);
221 chn->state = ECS_VIRQ;
222 chn->notify_vcpu_id = vcpu;
223 chn->u.virq = virq;
225 v->virq_to_evtchn[virq] = bind->port = port;
227 out:
228 spin_unlock(&d->evtchn_lock);
230 return rc;
231 }
234 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
235 {
236 struct evtchn *chn;
237 struct domain *d = current->domain;
238 int port, vcpu = bind->vcpu;
239 long rc = 0;
241 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
242 return -ENOENT;
244 spin_lock(&d->evtchn_lock);
246 if ( (port = get_free_port(d)) < 0 )
247 ERROR_EXIT(port);
249 chn = evtchn_from_port(d, port);
250 chn->state = ECS_IPI;
251 chn->notify_vcpu_id = vcpu;
253 bind->port = port;
255 out:
256 spin_unlock(&d->evtchn_lock);
258 return rc;
259 }
262 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
263 {
264 struct evtchn *chn;
265 struct domain *d = current->domain;
266 int port, pirq = bind->pirq;
267 long rc;
269 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
270 return -EINVAL;
272 if ( !irq_access_permitted(d, pirq) )
273 return -EPERM;
275 spin_lock(&d->evtchn_lock);
277 if ( d->pirq_to_evtchn[pirq] != 0 )
278 ERROR_EXIT(-EEXIST);
280 if ( (port = get_free_port(d)) < 0 )
281 ERROR_EXIT(port);
283 chn = evtchn_from_port(d, port);
285 d->pirq_to_evtchn[pirq] = port;
286 rc = pirq_guest_bind(d->vcpu[0], pirq,
287 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
288 if ( rc != 0 )
289 {
290 d->pirq_to_evtchn[pirq] = 0;
291 goto out;
292 }
294 chn->state = ECS_PIRQ;
295 chn->u.pirq = pirq;
297 bind->port = port;
299 out:
300 spin_unlock(&d->evtchn_lock);
302 return rc;
303 }
306 static long __evtchn_close(struct domain *d1, int port1)
307 {
308 struct domain *d2 = NULL;
309 struct vcpu *v;
310 struct evtchn *chn1, *chn2;
311 int port2;
312 long rc = 0;
314 again:
315 spin_lock(&d1->evtchn_lock);
317 if ( !port_is_valid(d1, port1) )
318 {
319 rc = -EINVAL;
320 goto out;
321 }
323 chn1 = evtchn_from_port(d1, port1);
324 switch ( chn1->state )
325 {
326 case ECS_FREE:
327 case ECS_RESERVED:
328 rc = -EINVAL;
329 goto out;
331 case ECS_UNBOUND:
332 break;
334 case ECS_PIRQ:
335 if ( (rc = pirq_guest_unbind(d1, chn1->u.pirq)) == 0 )
336 d1->pirq_to_evtchn[chn1->u.pirq] = 0;
337 break;
339 case ECS_VIRQ:
340 for_each_vcpu ( d1, v )
341 if ( v->virq_to_evtchn[chn1->u.virq] == port1 )
342 v->virq_to_evtchn[chn1->u.virq] = 0;
343 break;
345 case ECS_IPI:
346 break;
348 case ECS_INTERDOMAIN:
349 if ( d2 == NULL )
350 {
351 d2 = chn1->u.interdomain.remote_dom;
353 /* If we unlock d1 then we could lose d2. Must get a reference. */
354 if ( unlikely(!get_domain(d2)) )
355 {
356 /*
357 * Failed to obtain a reference. No matter: d2 must be dying
358 * and so will close this event channel for us.
359 */
360 d2 = NULL;
361 goto out;
362 }
364 if ( d1 < d2 )
365 {
366 spin_lock(&d2->evtchn_lock);
367 }
368 else if ( d1 != d2 )
369 {
370 spin_unlock(&d1->evtchn_lock);
371 spin_lock(&d2->evtchn_lock);
372 goto again;
373 }
374 }
375 else if ( d2 != chn1->u.interdomain.remote_dom )
376 {
377 /*
378 * We can only get here if the port was closed and re-bound after
379 * unlocking d1 but before locking d2 above. We could retry but
380 * it is easier to return the same error as if we had seen the
381 * port in ECS_CLOSED. It must have passed through that state for
382 * us to end up here, so it's a valid error to return.
383 */
384 BUG_ON(d1 != current->domain);
385 rc = -EINVAL;
386 goto out;
387 }
389 port2 = chn1->u.interdomain.remote_port;
390 BUG_ON(!port_is_valid(d2, port2));
392 chn2 = evtchn_from_port(d2, port2);
393 BUG_ON(chn2->state != ECS_INTERDOMAIN);
394 BUG_ON(chn2->u.interdomain.remote_dom != d1);
396 chn2->state = ECS_UNBOUND;
397 chn2->u.unbound.remote_domid = d1->domain_id;
398 break;
400 default:
401 BUG();
402 }
404 /* Reset binding to vcpu0 when the channel is freed. */
405 chn1->state = ECS_FREE;
406 chn1->notify_vcpu_id = 0;
408 out:
409 if ( d2 != NULL )
410 {
411 if ( d1 != d2 )
412 spin_unlock(&d2->evtchn_lock);
413 put_domain(d2);
414 }
416 spin_unlock(&d1->evtchn_lock);
418 return rc;
419 }
422 static long evtchn_close(evtchn_close_t *close)
423 {
424 return __evtchn_close(current->domain, close->port);
425 }
428 long evtchn_send(unsigned int lport)
429 {
430 struct evtchn *lchn, *rchn;
431 struct domain *ld = current->domain, *rd;
432 int rport, ret = 0;
434 spin_lock(&ld->evtchn_lock);
436 if ( unlikely(!port_is_valid(ld, lport)) )
437 {
438 spin_unlock(&ld->evtchn_lock);
439 return -EINVAL;
440 }
442 lchn = evtchn_from_port(ld, lport);
443 switch ( lchn->state )
444 {
445 case ECS_INTERDOMAIN:
446 rd = lchn->u.interdomain.remote_dom;
447 rport = lchn->u.interdomain.remote_port;
448 rchn = evtchn_from_port(rd, rport);
449 evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
450 break;
451 case ECS_IPI:
452 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
453 break;
454 case ECS_UNBOUND:
455 /* silently drop the notification */
456 break;
457 default:
458 ret = -EINVAL;
459 }
461 spin_unlock(&ld->evtchn_lock);
463 return ret;
464 }
467 void evtchn_set_pending(struct vcpu *v, int port)
468 {
469 struct domain *d = v->domain;
470 shared_info_t *s = d->shared_info;
472 /*
473 * The following bit operations must happen in strict order.
474 * NB. On x86, the atomic bit operations also act as memory barriers.
475 * There is therefore sufficiently strict ordering for this architecture --
476 * others may require explicit memory barriers.
477 */
479 if ( test_and_set_bit(port, &s->evtchn_pending[0]) )
480 return;
482 if ( !test_bit (port, &s->evtchn_mask[0]) &&
483 !test_and_set_bit(port / BITS_PER_LONG,
484 &v->vcpu_info->evtchn_pending_sel) &&
485 !test_and_set_bit(0, &v->vcpu_info->evtchn_upcall_pending) )
486 {
487 evtchn_notify(v);
488 }
489 else if ( unlikely(test_bit(_VCPUF_blocked, &v->vcpu_flags) &&
490 v->vcpu_info->evtchn_upcall_mask) )
491 {
492 /*
493 * Blocked and masked will usually mean that the VCPU executed
494 * SCHEDOP_poll. Kick the VCPU in case this port is in its poll list.
495 */
496 vcpu_unblock(v);
497 }
498 }
501 void send_guest_vcpu_virq(struct vcpu *v, int virq)
502 {
503 int port;
505 ASSERT(!virq_is_global(virq));
507 port = v->virq_to_evtchn[virq];
508 if ( unlikely(port == 0) )
509 return;
511 evtchn_set_pending(v, port);
512 }
514 void send_guest_global_virq(struct domain *d, int virq)
515 {
516 int port;
517 struct evtchn *chn;
519 ASSERT(virq_is_global(virq));
521 port = d->vcpu[0]->virq_to_evtchn[virq];
522 if ( unlikely(port == 0) )
523 return;
525 chn = evtchn_from_port(d, port);
526 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
527 }
530 void send_guest_pirq(struct domain *d, int pirq)
531 {
532 int port = d->pirq_to_evtchn[pirq];
533 struct evtchn *chn;
535 ASSERT(port != 0);
537 chn = evtchn_from_port(d, port);
538 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
539 }
542 static long evtchn_status(evtchn_status_t *status)
543 {
544 struct domain *d;
545 domid_t dom = status->dom;
546 int port = status->port;
547 struct evtchn *chn;
548 long rc = 0;
550 if ( dom == DOMID_SELF )
551 dom = current->domain->domain_id;
552 else if ( !IS_PRIV(current->domain) )
553 return -EPERM;
555 if ( (d = find_domain_by_id(dom)) == NULL )
556 return -ESRCH;
558 spin_lock(&d->evtchn_lock);
560 if ( !port_is_valid(d, port) )
561 {
562 rc = -EINVAL;
563 goto out;
564 }
566 chn = evtchn_from_port(d, port);
567 switch ( chn->state )
568 {
569 case ECS_FREE:
570 case ECS_RESERVED:
571 status->status = EVTCHNSTAT_closed;
572 break;
573 case ECS_UNBOUND:
574 status->status = EVTCHNSTAT_unbound;
575 status->u.unbound.dom = chn->u.unbound.remote_domid;
576 break;
577 case ECS_INTERDOMAIN:
578 status->status = EVTCHNSTAT_interdomain;
579 status->u.interdomain.dom =
580 chn->u.interdomain.remote_dom->domain_id;
581 status->u.interdomain.port = chn->u.interdomain.remote_port;
582 break;
583 case ECS_PIRQ:
584 status->status = EVTCHNSTAT_pirq;
585 status->u.pirq = chn->u.pirq;
586 break;
587 case ECS_VIRQ:
588 status->status = EVTCHNSTAT_virq;
589 status->u.virq = chn->u.virq;
590 break;
591 case ECS_IPI:
592 status->status = EVTCHNSTAT_ipi;
593 break;
594 default:
595 BUG();
596 }
598 status->vcpu = chn->notify_vcpu_id;
600 out:
601 spin_unlock(&d->evtchn_lock);
602 put_domain(d);
603 return rc;
604 }
607 long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id)
608 {
609 struct domain *d = current->domain;
610 struct evtchn *chn;
611 long rc = 0;
613 if ( (vcpu_id >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu_id] == NULL) )
614 return -ENOENT;
616 spin_lock(&d->evtchn_lock);
618 if ( !port_is_valid(d, port) )
619 {
620 rc = -EINVAL;
621 goto out;
622 }
624 chn = evtchn_from_port(d, port);
625 switch ( chn->state )
626 {
627 case ECS_VIRQ:
628 if ( virq_is_global(chn->u.virq) )
629 chn->notify_vcpu_id = vcpu_id;
630 else
631 rc = -EINVAL;
632 break;
633 case ECS_UNBOUND:
634 case ECS_INTERDOMAIN:
635 case ECS_PIRQ:
636 chn->notify_vcpu_id = vcpu_id;
637 break;
638 default:
639 rc = -EINVAL;
640 break;
641 }
643 out:
644 spin_unlock(&d->evtchn_lock);
645 return rc;
646 }
649 static long evtchn_unmask(evtchn_unmask_t *unmask)
650 {
651 struct domain *d = current->domain;
652 shared_info_t *s = d->shared_info;
653 int port = unmask->port;
654 struct vcpu *v;
656 spin_lock(&d->evtchn_lock);
658 if ( unlikely(!port_is_valid(d, port)) )
659 {
660 spin_unlock(&d->evtchn_lock);
661 return -EINVAL;
662 }
664 v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
666 /*
667 * These operations must happen in strict order. Based on
668 * include/xen/event.h:evtchn_set_pending().
669 */
670 if ( test_and_clear_bit(port, &s->evtchn_mask[0]) &&
671 test_bit (port, &s->evtchn_pending[0]) &&
672 !test_and_set_bit (port / BITS_PER_LONG,
673 &v->vcpu_info->evtchn_pending_sel) &&
674 !test_and_set_bit (0, &v->vcpu_info->evtchn_upcall_pending) )
675 {
676 evtchn_notify(v);
677 }
679 spin_unlock(&d->evtchn_lock);
681 return 0;
682 }
685 long do_event_channel_op(GUEST_HANDLE(evtchn_op_t) uop)
686 {
687 long rc;
688 struct evtchn_op op;
690 if ( copy_from_guest(&op, uop, 1) != 0 )
691 return -EFAULT;
693 if (acm_pre_event_channel(&op))
694 return -EACCES;
696 switch ( op.cmd )
697 {
698 case EVTCHNOP_alloc_unbound:
699 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
700 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
701 rc = -EFAULT; /* Cleaning up here would be a mess! */
702 break;
704 case EVTCHNOP_bind_interdomain:
705 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
706 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
707 rc = -EFAULT; /* Cleaning up here would be a mess! */
708 break;
710 case EVTCHNOP_bind_virq:
711 rc = evtchn_bind_virq(&op.u.bind_virq);
712 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
713 rc = -EFAULT; /* Cleaning up here would be a mess! */
714 break;
716 case EVTCHNOP_bind_ipi:
717 rc = evtchn_bind_ipi(&op.u.bind_ipi);
718 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
719 rc = -EFAULT; /* Cleaning up here would be a mess! */
720 break;
722 case EVTCHNOP_bind_pirq:
723 rc = evtchn_bind_pirq(&op.u.bind_pirq);
724 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
725 rc = -EFAULT; /* Cleaning up here would be a mess! */
726 break;
728 case EVTCHNOP_close:
729 rc = evtchn_close(&op.u.close);
730 break;
732 case EVTCHNOP_send:
733 rc = evtchn_send(op.u.send.port);
734 break;
736 case EVTCHNOP_status:
737 rc = evtchn_status(&op.u.status);
738 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
739 rc = -EFAULT;
740 break;
742 case EVTCHNOP_bind_vcpu:
743 rc = evtchn_bind_vcpu(op.u.bind_vcpu.port, op.u.bind_vcpu.vcpu);
744 break;
746 case EVTCHNOP_unmask:
747 rc = evtchn_unmask(&op.u.unmask);
748 break;
750 default:
751 rc = -ENOSYS;
752 break;
753 }
755 return rc;
756 }
759 void evtchn_notify_reserved_port(struct domain *d, int port)
760 {
761 struct evtchn *chn = evtchn_from_port(d, port);
762 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
763 }
766 int evtchn_init(struct domain *d)
767 {
768 spin_lock_init(&d->evtchn_lock);
769 if ( get_free_port(d) != 0 )
770 return -EINVAL;
771 evtchn_from_port(d, 0)->state = ECS_RESERVED;
772 return 0;
773 }
776 void evtchn_destroy(struct domain *d)
777 {
778 int i;
780 for ( i = 0; port_is_valid(d, i); i++ )
781 (void)__evtchn_close(d, i);
783 for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
784 xfree(d->evtchn[i]);
785 }
787 /*
788 * Local variables:
789 * mode: C
790 * c-set-style: "BSD"
791 * c-basic-offset: 4
792 * tab-width: 4
793 * indent-tabs-mode: nil
794 * End:
795 */