ia64/xen-unstable

annotate xen/common/event_channel.c @ 8232:99b9046a8df2

Add a comment to tricky corner case in evtchn_close().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Dec 04 11:54:04 2005 +0100 (2005-12-04)
parents fcb7e5616102
children 455b2b93542c
rev   line source
kaf24@954 1 /******************************************************************************
kaf24@954 2 * event_channel.c
kaf24@954 3 *
kaf24@1509 4 * Event notifications from VIRQs, PIRQs, and other domains.
kaf24@954 5 *
kaf24@1127 6 * Copyright (c) 2003-2004, K A Fraser.
kaf24@954 7 *
kaf24@954 8 * This program is distributed in the hope that it will be useful,
kaf24@954 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@954 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kaf24@954 11 * GNU General Public License for more details.
kaf24@954 12 *
kaf24@954 13 * You should have received a copy of the GNU General Public License
kaf24@954 14 * along with this program; if not, write to the Free Software
kaf24@954 15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@954 16 */
kaf24@954 17
kaf24@1210 18 #include <xen/config.h>
kaf24@1210 19 #include <xen/init.h>
kaf24@1210 20 #include <xen/lib.h>
kaf24@1210 21 #include <xen/errno.h>
kaf24@1210 22 #include <xen/sched.h>
kaf24@1210 23 #include <xen/event.h>
kaf24@1239 24 #include <xen/irq.h>
cl349@5291 25 #include <asm/current.h>
kaf24@954 26
kaf24@2789 27 #include <public/xen.h>
kaf24@2789 28 #include <public/event_channel.h>
smh22@5514 29 #include <acm/acm_hooks.h>
kaf24@1127 30
kaf24@5308 31 #define bucket_from_port(d,p) \
kaf24@5308 32 ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
kaf24@5308 33 #define port_is_valid(d,p) \
kaf24@5308 34 (((p) >= 0) && ((p) < MAX_EVTCHNS) && \
kaf24@5308 35 (bucket_from_port(d,p) != NULL))
kaf24@5308 36 #define evtchn_from_port(d,p) \
kaf24@5308 37 (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
kaf24@1127 38
kaf24@7245 39 #define ERROR_EXIT(_errno) \
kaf24@7245 40 do { \
kaf24@7245 41 DPRINTK("EVTCHNOP failure: domain %d, error %d, line %d\n", \
kaf24@7245 42 current->domain->domain_id, (_errno), __LINE__); \
kaf24@7245 43 rc = (_errno); \
kaf24@7245 44 goto out; \
kaf24@7245 45 } while ( 0 )
kaf24@5325 46
kaf24@5308 47 static int get_free_port(struct domain *d)
kaf24@5308 48 {
kaf24@5308 49 struct evtchn *chn;
kaf24@5308 50 int port;
cl349@3114 51
kaf24@5308 52 for ( port = 0; port_is_valid(d, port); port++ )
kaf24@5308 53 if ( evtchn_from_port(d, port)->state == ECS_FREE )
kaf24@5308 54 return port;
kaf24@1127 55
kaf24@5308 56 if ( port == MAX_EVTCHNS )
kaf24@5308 57 return -ENOSPC;
kaf24@1127 58
kaf24@5308 59 chn = xmalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
kaf24@5308 60 if ( unlikely(chn == NULL) )
kaf24@5308 61 return -ENOMEM;
kaf24@5308 62 memset(chn, 0, EVTCHNS_PER_BUCKET * sizeof(*chn));
kaf24@5308 63 bucket_from_port(d, port) = chn;
kaf24@1127 64
kaf24@1127 65 return port;
kaf24@1127 66 }
kaf24@1127 67
kaf24@2713 68
kaf24@2713 69 static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
kaf24@2713 70 {
kaf24@5308 71 struct evtchn *chn;
kaf24@7232 72 struct domain *d;
kaf24@7250 73 int port;
kaf24@7232 74 domid_t dom = alloc->dom;
kaf24@5325 75 long rc = 0;
kaf24@2713 76
kaf24@7232 77 if ( dom == DOMID_SELF )
kaf24@7232 78 dom = current->domain->domain_id;
kaf24@7232 79 else if ( !IS_PRIV(current->domain) )
kaf24@7232 80 return -EPERM;
kaf24@7232 81
kaf24@7232 82 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@7232 83 return -ESRCH;
kaf24@7232 84
kaf24@5308 85 spin_lock(&d->evtchn_lock);
kaf24@2713 86
kaf24@7250 87 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 88 ERROR_EXIT(port);
kaf24@5325 89 chn = evtchn_from_port(d, port);
kaf24@5325 90
kaf24@7250 91 chn->state = ECS_UNBOUND;
kaf24@7421 92 if ( (chn->u.unbound.remote_domid = alloc->remote_dom) == DOMID_SELF )
kaf24@7421 93 chn->u.unbound.remote_domid = current->domain->domain_id;
kaf24@5325 94
kaf24@7250 95 alloc->port = port;
kaf24@2713 96
kaf24@5325 97 out:
kaf24@5308 98 spin_unlock(&d->evtchn_lock);
kaf24@2713 99
kaf24@7232 100 put_domain(d);
kaf24@7232 101
kaf24@5325 102 return rc;
kaf24@2713 103 }
kaf24@2713 104
kaf24@2713 105
kaf24@1218 106 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
kaf24@1127 107 {
kaf24@7250 108 struct evtchn *lchn, *rchn;
kaf24@7250 109 struct domain *ld = current->domain, *rd;
kaf24@7250 110 int lport, rport = bind->remote_port;
kaf24@7421 111 domid_t rdom = bind->remote_dom;
kaf24@1506 112 long rc = 0;
kaf24@954 113
kaf24@7421 114 if ( rdom == DOMID_SELF )
kaf24@7421 115 rdom = current->domain->domain_id;
kaf24@7421 116
kaf24@7421 117 if ( (rd = find_domain_by_id(rdom)) == NULL )
kaf24@1127 118 return -ESRCH;
kaf24@1127 119
kaf24@1127 120 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@7250 121 if ( ld < rd )
kaf24@954 122 {
kaf24@7250 123 spin_lock(&ld->evtchn_lock);
kaf24@7250 124 spin_lock(&rd->evtchn_lock);
kaf24@954 125 }
kaf24@954 126 else
kaf24@954 127 {
kaf24@7250 128 if ( ld != rd )
kaf24@7250 129 spin_lock(&rd->evtchn_lock);
kaf24@7250 130 spin_lock(&ld->evtchn_lock);
kaf24@954 131 }
kaf24@954 132
kaf24@7250 133 if ( (lport = get_free_port(ld)) < 0 )
kaf24@7250 134 ERROR_EXIT(lport);
kaf24@7250 135 lchn = evtchn_from_port(ld, lport);
kaf24@2713 136
kaf24@7250 137 if ( !port_is_valid(rd, rport) )
kaf24@2713 138 ERROR_EXIT(-EINVAL);
kaf24@7250 139 rchn = evtchn_from_port(rd, rport);
kaf24@7250 140 if ( (rchn->state != ECS_UNBOUND) ||
kaf24@7250 141 (rchn->u.unbound.remote_domid != ld->domain_id) )
kaf24@7250 142 ERROR_EXIT(-EINVAL);
kaf24@954 143
kaf24@7250 144 lchn->u.interdomain.remote_dom = rd;
kaf24@7250 145 lchn->u.interdomain.remote_port = (u16)rport;
kaf24@7250 146 lchn->state = ECS_INTERDOMAIN;
kaf24@7250 147
kaf24@7250 148 rchn->u.interdomain.remote_dom = ld;
kaf24@7250 149 rchn->u.interdomain.remote_port = (u16)lport;
kaf24@7250 150 rchn->state = ECS_INTERDOMAIN;
kaf24@954 151
kaf24@2713 152 /*
kaf24@7250 153 * We may have lost notifications on the remote unbound port. Fix that up
kaf24@7250 154 * here by conservatively always setting a notification on the local port.
kaf24@2713 155 */
kaf24@7250 156 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
kaf24@2713 157
kaf24@7250 158 bind->local_port = lport;
kaf24@1127 159
kaf24@954 160 out:
kaf24@7250 161 spin_unlock(&ld->evtchn_lock);
kaf24@7250 162 if ( ld != rd )
kaf24@7250 163 spin_unlock(&rd->evtchn_lock);
kaf24@1127 164
kaf24@7250 165 put_domain(rd);
kaf24@954 166
kaf24@954 167 return rc;
kaf24@954 168 }
kaf24@954 169
kaf24@954 170
kaf24@1218 171 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 172 {
kaf24@5308 173 struct evtchn *chn;
kaf24@7204 174 struct vcpu *v;
kaf24@7204 175 struct domain *d = current->domain;
kaf24@7250 176 int port, virq = bind->virq, vcpu = bind->vcpu;
kaf24@7250 177 long rc = 0;
kaf24@1218 178
kaf24@5289 179 if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
kaf24@1218 180 return -EINVAL;
kaf24@1218 181
kaf24@7250 182 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
kaf24@7204 183 return -ENOENT;
cl349@6680 184
kaf24@5308 185 spin_lock(&d->evtchn_lock);
kaf24@1218 186
kaf24@7250 187 if ( v->virq_to_evtchn[virq] != 0 )
kaf24@7250 188 ERROR_EXIT(-EEXIST);
kaf24@7250 189
kaf24@7250 190 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 191 ERROR_EXIT(port);
kaf24@1218 192
kaf24@5308 193 chn = evtchn_from_port(d, port);
kaf24@5308 194 chn->state = ECS_VIRQ;
kaf24@7250 195 chn->notify_vcpu_id = vcpu;
kaf24@5308 196 chn->u.virq = virq;
kaf24@1218 197
kaf24@7250 198 v->virq_to_evtchn[virq] = bind->port = port;
kaf24@1218 199
kaf24@1218 200 out:
kaf24@5308 201 spin_unlock(&d->evtchn_lock);
kaf24@1218 202
kaf24@7250 203 return rc;
cl349@2932 204 }
cl349@2932 205
kaf24@5308 206
cl349@2932 207 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 208 {
kaf24@5308 209 struct evtchn *chn;
kaf24@5308 210 struct domain *d = current->domain;
kaf24@7250 211 int port, vcpu = bind->vcpu;
kaf24@7250 212 long rc = 0;
kaf24@4202 213
kaf24@7250 214 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
kaf24@7204 215 return -ENOENT;
kaf24@7204 216
kaf24@5308 217 spin_lock(&d->evtchn_lock);
cl349@2932 218
kaf24@7250 219 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 220 ERROR_EXIT(port);
cl349@2932 221
kaf24@7250 222 chn = evtchn_from_port(d, port);
kaf24@7250 223 chn->state = ECS_IPI;
kaf24@7250 224 chn->notify_vcpu_id = vcpu;
kaf24@7250 225
kaf24@7250 226 bind->port = port;
kaf24@7250 227
kaf24@7250 228 out:
kaf24@5308 229 spin_unlock(&d->evtchn_lock);
cl349@2932 230
kaf24@7250 231 return rc;
kaf24@1218 232 }
kaf24@1218 233
kaf24@1218 234
kaf24@1235 235 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 236 {
kaf24@5308 237 struct evtchn *chn;
cl349@2919 238 struct domain *d = current->domain;
kaf24@7250 239 int port, pirq = bind->pirq;
kaf24@7250 240 long rc;
kaf24@1235 241
kaf24@1506 242 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 243 return -EINVAL;
kaf24@1235 244
kaf24@5308 245 spin_lock(&d->evtchn_lock);
kaf24@1235 246
kaf24@7250 247 if ( d->pirq_to_evtchn[pirq] != 0 )
kaf24@7250 248 ERROR_EXIT(-EEXIST);
kaf24@7250 249
kaf24@7250 250 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 251 ERROR_EXIT(port);
kaf24@1235 252
kaf24@5308 253 chn = evtchn_from_port(d, port);
kaf24@5308 254
kaf24@1506 255 d->pirq_to_evtchn[pirq] = port;
sos22@5700 256 rc = pirq_guest_bind(d->vcpu[0], pirq,
kaf24@1253 257 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 258 if ( rc != 0 )
kaf24@1239 259 {
kaf24@1506 260 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 261 goto out;
kaf24@1239 262 }
kaf24@1239 263
kaf24@5308 264 chn->state = ECS_PIRQ;
kaf24@5308 265 chn->u.pirq = pirq;
kaf24@1235 266
kaf24@7250 267 bind->port = port;
kaf24@7250 268
kaf24@1235 269 out:
kaf24@5308 270 spin_unlock(&d->evtchn_lock);
kaf24@1235 271
kaf24@7250 272 return rc;
kaf24@1235 273 }
kaf24@1235 274
kaf24@1235 275
kaf24@1506 276 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 277 {
kaf24@5308 278 struct domain *d2 = NULL;
kaf24@5308 279 struct vcpu *v;
kaf24@5308 280 struct evtchn *chn1, *chn2;
kaf24@5308 281 int port2;
kaf24@5308 282 long rc = 0;
kaf24@954 283
kaf24@954 284 again:
kaf24@5308 285 spin_lock(&d1->evtchn_lock);
kaf24@954 286
kaf24@5308 287 if ( !port_is_valid(d1, port1) )
kaf24@954 288 {
kaf24@954 289 rc = -EINVAL;
kaf24@954 290 goto out;
kaf24@954 291 }
kaf24@954 292
kaf24@5308 293 chn1 = evtchn_from_port(d1, port1);
kaf24@5308 294 switch ( chn1->state )
kaf24@954 295 {
kaf24@1218 296 case ECS_FREE:
cl349@3297 297 case ECS_RESERVED:
kaf24@1218 298 rc = -EINVAL;
kaf24@1218 299 goto out;
kaf24@1218 300
kaf24@1218 301 case ECS_UNBOUND:
kaf24@1218 302 break;
kaf24@1218 303
kaf24@1218 304 case ECS_PIRQ:
kaf24@5308 305 if ( (rc = pirq_guest_unbind(d1, chn1->u.pirq)) == 0 )
kaf24@5308 306 d1->pirq_to_evtchn[chn1->u.pirq] = 0;
kaf24@1218 307 break;
kaf24@1218 308
kaf24@1218 309 case ECS_VIRQ:
kaf24@5289 310 for_each_vcpu ( d1, v )
kaf24@5308 311 if ( v->virq_to_evtchn[chn1->u.virq] == port1 )
kaf24@5308 312 v->virq_to_evtchn[chn1->u.virq] = 0;
kaf24@1218 313 break;
kaf24@1218 314
cl349@2932 315 case ECS_IPI:
cl349@2932 316 break;
cl349@2932 317
kaf24@1218 318 case ECS_INTERDOMAIN:
kaf24@1506 319 if ( d2 == NULL )
kaf24@954 320 {
kaf24@5308 321 d2 = chn1->u.interdomain.remote_dom;
kaf24@1505 322
kaf24@1506 323 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 324 if ( unlikely(!get_domain(d2)) )
kaf24@1505 325 {
kaf24@1505 326 /*
kaf24@1506 327 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 328 * and so will close this event channel for us.
kaf24@1505 329 */
kaf24@1506 330 d2 = NULL;
kaf24@1505 331 goto out;
kaf24@1505 332 }
kaf24@1127 333
kaf24@1542 334 if ( d1 < d2 )
kaf24@954 335 {
kaf24@5308 336 spin_lock(&d2->evtchn_lock);
kaf24@954 337 }
kaf24@1506 338 else if ( d1 != d2 )
kaf24@954 339 {
kaf24@5308 340 spin_unlock(&d1->evtchn_lock);
kaf24@5308 341 spin_lock(&d2->evtchn_lock);
kaf24@954 342 goto again;
kaf24@954 343 }
kaf24@954 344 }
kaf24@5308 345 else if ( d2 != chn1->u.interdomain.remote_dom )
kaf24@954 346 {
kaf24@8232 347 /*
kaf24@8232 348 * We can only get here if the port was closed and re-bound after
kaf24@8232 349 * unlocking d1 but before locking d2 above. We could retry but
kaf24@8232 350 * it is easier to return the same error as if we had seen the
kaf24@8232 351 * port in ECS_CLOSED. It must have passed through that state for
kaf24@8232 352 * us to end up here, so it's a valid error to return.
kaf24@8232 353 */
kaf24@8232 354 BUG_ON(d1 != current->domain);
kaf24@954 355 rc = -EINVAL;
kaf24@954 356 goto out;
kaf24@954 357 }
kaf24@1505 358
kaf24@5308 359 port2 = chn1->u.interdomain.remote_port;
kaf24@5308 360 BUG_ON(!port_is_valid(d2, port2));
kaf24@954 361
kaf24@5308 362 chn2 = evtchn_from_port(d2, port2);
kaf24@5308 363 BUG_ON(chn2->state != ECS_INTERDOMAIN);
kaf24@5308 364 BUG_ON(chn2->u.interdomain.remote_dom != d1);
kaf24@954 365
kaf24@5308 366 chn2->state = ECS_UNBOUND;
kaf24@5308 367 chn2->u.unbound.remote_domid = d1->domain_id;
kaf24@1218 368 break;
kaf24@1218 369
kaf24@1218 370 default:
kaf24@1218 371 BUG();
kaf24@954 372 }
kaf24@954 373
kaf24@5703 374 /* Reset binding to vcpu0 when the channel is freed. */
kaf24@5703 375 chn1->state = ECS_FREE;
kaf24@5703 376 chn1->notify_vcpu_id = 0;
kaf24@1133 377
kaf24@954 378 out:
kaf24@1506 379 if ( d2 != NULL )
kaf24@954 380 {
kaf24@1506 381 if ( d1 != d2 )
kaf24@5308 382 spin_unlock(&d2->evtchn_lock);
kaf24@1506 383 put_domain(d2);
kaf24@954 384 }
kaf24@954 385
kaf24@5308 386 spin_unlock(&d1->evtchn_lock);
kaf24@1145 387
kaf24@954 388 return rc;
kaf24@954 389 }
kaf24@954 390
kaf24@954 391
kaf24@1218 392 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 393 {
kaf24@7250 394 return __evtchn_close(current->domain, close->port);
kaf24@1127 395 }
kaf24@1127 396
kaf24@1127 397
iap10@3290 398 long evtchn_send(int lport)
kaf24@954 399 {
kaf24@5308 400 struct evtchn *lchn, *rchn;
kaf24@5308 401 struct domain *ld = current->domain, *rd;
cl349@2937 402 int rport, ret = 0;
kaf24@954 403
kaf24@5308 404 spin_lock(&ld->evtchn_lock);
kaf24@954 405
kaf24@5308 406 if ( unlikely(!port_is_valid(ld, lport)) )
kaf24@954 407 {
kaf24@5308 408 spin_unlock(&ld->evtchn_lock);
kaf24@954 409 return -EINVAL;
kaf24@954 410 }
kaf24@954 411
kaf24@5308 412 lchn = evtchn_from_port(ld, lport);
kaf24@5308 413 switch ( lchn->state )
cl349@2937 414 {
cl349@2937 415 case ECS_INTERDOMAIN:
kaf24@5308 416 rd = lchn->u.interdomain.remote_dom;
kaf24@5308 417 rport = lchn->u.interdomain.remote_port;
kaf24@5308 418 rchn = evtchn_from_port(rd, rport);
kaf24@5308 419 evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
cl349@2937 420 break;
cl349@2937 421 case ECS_IPI:
kaf24@5308 422 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
cl349@2937 423 break;
kaf24@7250 424 case ECS_UNBOUND:
kaf24@7250 425 /* silently drop the notification */
kaf24@7250 426 break;
cl349@2937 427 default:
cl349@2937 428 ret = -EINVAL;
cl349@2937 429 }
kaf24@954 430
kaf24@5308 431 spin_unlock(&ld->evtchn_lock);
kaf24@954 432
cl349@2937 433 return ret;
kaf24@954 434 }
kaf24@954 435
kaf24@5308 436 void send_guest_pirq(struct domain *d, int pirq)
kaf24@5308 437 {
kaf24@5308 438 int port = d->pirq_to_evtchn[pirq];
kaf24@5308 439 struct evtchn *chn = evtchn_from_port(d, port);
kaf24@5308 440 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
kaf24@5308 441 }
kaf24@954 442
kaf24@1218 443 static long evtchn_status(evtchn_status_t *status)
kaf24@954 444 {
kaf24@1506 445 struct domain *d;
kaf24@1506 446 domid_t dom = status->dom;
kaf24@1506 447 int port = status->port;
kaf24@5308 448 struct evtchn *chn;
kaf24@1506 449 long rc = 0;
kaf24@1127 450
kaf24@1129 451 if ( dom == DOMID_SELF )
kaf24@4877 452 dom = current->domain->domain_id;
cl349@2919 453 else if ( !IS_PRIV(current->domain) )
kaf24@1127 454 return -EPERM;
kaf24@1127 455
kaf24@1506 456 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 457 return -ESRCH;
kaf24@954 458
kaf24@5308 459 spin_lock(&d->evtchn_lock);
kaf24@954 460
kaf24@5308 461 if ( !port_is_valid(d, port) )
kaf24@954 462 {
kaf24@1266 463 rc = -EINVAL;
kaf24@1266 464 goto out;
kaf24@1127 465 }
kaf24@1127 466
kaf24@5308 467 chn = evtchn_from_port(d, port);
kaf24@5308 468 switch ( chn->state )
kaf24@1127 469 {
kaf24@1127 470 case ECS_FREE:
cl349@3297 471 case ECS_RESERVED:
kaf24@1127 472 status->status = EVTCHNSTAT_closed;
kaf24@1127 473 break;
kaf24@1218 474 case ECS_UNBOUND:
kaf24@1218 475 status->status = EVTCHNSTAT_unbound;
kaf24@5308 476 status->u.unbound.dom = chn->u.unbound.remote_domid;
kaf24@1127 477 break;
kaf24@1218 478 case ECS_INTERDOMAIN:
kaf24@1218 479 status->status = EVTCHNSTAT_interdomain;
cl349@2924 480 status->u.interdomain.dom =
kaf24@5308 481 chn->u.interdomain.remote_dom->domain_id;
kaf24@5308 482 status->u.interdomain.port = chn->u.interdomain.remote_port;
kaf24@1218 483 break;
kaf24@1218 484 case ECS_PIRQ:
kaf24@1218 485 status->status = EVTCHNSTAT_pirq;
kaf24@5308 486 status->u.pirq = chn->u.pirq;
kaf24@1218 487 break;
kaf24@1218 488 case ECS_VIRQ:
kaf24@1218 489 status->status = EVTCHNSTAT_virq;
kaf24@5308 490 status->u.virq = chn->u.virq;
kaf24@1127 491 break;
cl349@2932 492 case ECS_IPI:
kaf24@5703 493 status->status = EVTCHNSTAT_ipi;
cl349@2932 494 break;
kaf24@1127 495 default:
kaf24@1127 496 BUG();
kaf24@954 497 }
kaf24@954 498
kaf24@5703 499 status->vcpu = chn->notify_vcpu_id;
kaf24@5703 500
kaf24@1266 501 out:
kaf24@5308 502 spin_unlock(&d->evtchn_lock);
kaf24@1506 503 put_domain(d);
kaf24@1266 504 return rc;
kaf24@954 505 }
kaf24@954 506
kaf24@5703 507 static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
iap10@5691 508 {
iap10@5691 509 struct domain *d = current->domain;
iap10@5691 510 int port = bind->port;
iap10@5691 511 int vcpu = bind->vcpu;
iap10@5691 512 struct evtchn *chn;
kaf24@5703 513 long rc = 0;
kaf24@5703 514
kaf24@7250 515 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
kaf24@7250 516 return -ENOENT;
iap10@5691 517
iap10@5691 518 spin_lock(&d->evtchn_lock);
iap10@5691 519
iap10@5691 520 if ( !port_is_valid(d, port) )
iap10@5691 521 {
iap10@5691 522 rc = -EINVAL;
iap10@5691 523 goto out;
iap10@5691 524 }
iap10@5691 525
iap10@5691 526 chn = evtchn_from_port(d, port);
kaf24@5703 527 switch ( chn->state )
kaf24@5703 528 {
kaf24@5703 529 case ECS_UNBOUND:
kaf24@5703 530 case ECS_INTERDOMAIN:
kaf24@5703 531 case ECS_PIRQ:
kaf24@5703 532 chn->notify_vcpu_id = vcpu;
kaf24@5703 533 break;
kaf24@5703 534 default:
kaf24@5703 535 rc = -EINVAL;
kaf24@5703 536 break;
kaf24@5703 537 }
iap10@5691 538
iap10@5691 539 out:
iap10@5691 540 spin_unlock(&d->evtchn_lock);
iap10@5691 541 return rc;
iap10@5691 542 }
kaf24@954 543
kaf24@1127 544 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 545 {
kaf24@954 546 long rc;
kaf24@1127 547 evtchn_op_t op;
kaf24@954 548
kaf24@1127 549 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 550 return -EFAULT;
kaf24@1127 551
smh22@5514 552 if (acm_pre_event_channel(&op))
smh22@5514 553 return -EACCES;
smh22@5514 554
kaf24@1127 555 switch ( op.cmd )
kaf24@954 556 {
kaf24@2713 557 case EVTCHNOP_alloc_unbound:
kaf24@2713 558 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 559 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 560 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 561 break;
kaf24@2713 562
kaf24@1218 563 case EVTCHNOP_bind_interdomain:
kaf24@1218 564 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 565 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 566 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 567 break;
kaf24@1218 568
kaf24@1218 569 case EVTCHNOP_bind_virq:
kaf24@1218 570 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 571 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 572 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 573 break;
kaf24@1235 574
cl349@2932 575 case EVTCHNOP_bind_ipi:
cl349@2932 576 rc = evtchn_bind_ipi(&op.u.bind_ipi);
cl349@2932 577 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
cl349@2932 578 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 579 break;
cl349@2932 580
kaf24@1235 581 case EVTCHNOP_bind_pirq:
kaf24@1235 582 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 583 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 584 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 585 break;
kaf24@954 586
kaf24@954 587 case EVTCHNOP_close:
kaf24@1218 588 rc = evtchn_close(&op.u.close);
kaf24@954 589 break;
kaf24@954 590
kaf24@954 591 case EVTCHNOP_send:
kaf24@7250 592 rc = evtchn_send(op.u.send.port);
kaf24@954 593 break;
kaf24@954 594
kaf24@954 595 case EVTCHNOP_status:
kaf24@1218 596 rc = evtchn_status(&op.u.status);
kaf24@1235 597 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 598 rc = -EFAULT;
kaf24@954 599 break;
kaf24@954 600
kaf24@5703 601 case EVTCHNOP_bind_vcpu:
kaf24@5703 602 rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
iap10@5691 603 break;
iap10@5691 604
kaf24@954 605 default:
kaf24@954 606 rc = -ENOSYS;
kaf24@954 607 break;
kaf24@954 608 }
kaf24@954 609
kaf24@954 610 return rc;
kaf24@954 611 }
kaf24@954 612
kaf24@954 613
kaf24@5308 614 int evtchn_init(struct domain *d)
kaf24@1218 615 {
kaf24@5308 616 spin_lock_init(&d->evtchn_lock);
kaf24@5308 617 if ( get_free_port(d) != 0 )
cl349@3291 618 return -EINVAL;
kaf24@5308 619 evtchn_from_port(d, 0)->state = ECS_RESERVED;
cl349@3291 620 return 0;
kaf24@1218 621 }
kaf24@1218 622
kaf24@1218 623
kaf24@5308 624 void evtchn_destroy(struct domain *d)
kaf24@954 625 {
kaf24@954 626 int i;
kaf24@5308 627
kaf24@5308 628 for ( i = 0; port_is_valid(d, i); i++ )
kaf24@1506 629 (void)__evtchn_close(d, i);
kaf24@5308 630
kaf24@5308 631 for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
kaf24@7782 632 xfree(d->evtchn[i]);
kaf24@954 633 }
kaf24@3914 634
kaf24@3914 635 /*
kaf24@3914 636 * Local variables:
kaf24@3914 637 * mode: C
kaf24@3914 638 * c-set-style: "BSD"
kaf24@3914 639 * c-basic-offset: 4
kaf24@3914 640 * tab-width: 4
kaf24@3914 641 * indent-tabs-mode: nil
kaf24@3988 642 * End:
kaf24@3914 643 */