ia64/xen-unstable

annotate xen/common/event_channel.c @ 9596:e1152d55ea31

Add new interface for allocating reserved event-channel
ports to arbitrary Xen subsystems.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 05 17:41:51 2006 +0100 (2006-04-05)
parents c445d4a0dd76
children 8f7aad20b4a5
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@8351 6 * Copyright (c) 2003-2005, 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>
kaf24@8468 25 #include <xen/iocap.h>
kaf24@9183 26 #include <xen/guest_access.h>
cl349@5291 27 #include <asm/current.h>
kaf24@954 28
kaf24@2789 29 #include <public/xen.h>
kaf24@2789 30 #include <public/event_channel.h>
smh22@5514 31 #include <acm/acm_hooks.h>
kaf24@1127 32
kaf24@5308 33 #define bucket_from_port(d,p) \
kaf24@5308 34 ((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
kaf24@5308 35 #define port_is_valid(d,p) \
kaf24@5308 36 (((p) >= 0) && ((p) < MAX_EVTCHNS) && \
kaf24@5308 37 (bucket_from_port(d,p) != NULL))
kaf24@5308 38 #define evtchn_from_port(d,p) \
kaf24@5308 39 (&(bucket_from_port(d,p))[(p)&(EVTCHNS_PER_BUCKET-1)])
kaf24@1127 40
kaf24@7245 41 #define ERROR_EXIT(_errno) \
kaf24@7245 42 do { \
kaf24@7245 43 DPRINTK("EVTCHNOP failure: domain %d, error %d, line %d\n", \
kaf24@7245 44 current->domain->domain_id, (_errno), __LINE__); \
kaf24@7245 45 rc = (_errno); \
kaf24@7245 46 goto out; \
kaf24@7245 47 } while ( 0 )
kaf24@5325 48
kaf24@9596 49
kaf24@5308 50 static int get_free_port(struct domain *d)
kaf24@5308 51 {
kaf24@5308 52 struct evtchn *chn;
kaf24@5308 53 int port;
cl349@3114 54
kaf24@5308 55 for ( port = 0; port_is_valid(d, port); port++ )
kaf24@5308 56 if ( evtchn_from_port(d, port)->state == ECS_FREE )
kaf24@5308 57 return port;
kaf24@1127 58
kaf24@5308 59 if ( port == MAX_EVTCHNS )
kaf24@5308 60 return -ENOSPC;
kaf24@1127 61
kaf24@5308 62 chn = xmalloc_array(struct evtchn, EVTCHNS_PER_BUCKET);
kaf24@5308 63 if ( unlikely(chn == NULL) )
kaf24@5308 64 return -ENOMEM;
kaf24@5308 65 memset(chn, 0, EVTCHNS_PER_BUCKET * sizeof(*chn));
kaf24@5308 66 bucket_from_port(d, port) = chn;
kaf24@1127 67
kaf24@1127 68 return port;
kaf24@1127 69 }
kaf24@1127 70
kaf24@2713 71
kaf24@2713 72 static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
kaf24@2713 73 {
kaf24@5308 74 struct evtchn *chn;
kaf24@7232 75 struct domain *d;
kaf24@7250 76 int port;
kaf24@7232 77 domid_t dom = alloc->dom;
kaf24@5325 78 long rc = 0;
kaf24@2713 79
kaf24@7232 80 if ( dom == DOMID_SELF )
kaf24@7232 81 dom = current->domain->domain_id;
kaf24@7232 82 else if ( !IS_PRIV(current->domain) )
kaf24@7232 83 return -EPERM;
kaf24@7232 84
kaf24@7232 85 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@7232 86 return -ESRCH;
kaf24@7232 87
kaf24@5308 88 spin_lock(&d->evtchn_lock);
kaf24@2713 89
kaf24@7250 90 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 91 ERROR_EXIT(port);
kaf24@5325 92 chn = evtchn_from_port(d, port);
kaf24@5325 93
kaf24@7250 94 chn->state = ECS_UNBOUND;
kaf24@7421 95 if ( (chn->u.unbound.remote_domid = alloc->remote_dom) == DOMID_SELF )
kaf24@7421 96 chn->u.unbound.remote_domid = current->domain->domain_id;
kaf24@5325 97
kaf24@7250 98 alloc->port = port;
kaf24@2713 99
kaf24@5325 100 out:
kaf24@5308 101 spin_unlock(&d->evtchn_lock);
kaf24@2713 102
kaf24@7232 103 put_domain(d);
kaf24@7232 104
kaf24@5325 105 return rc;
kaf24@2713 106 }
kaf24@2713 107
kaf24@2713 108
kaf24@1218 109 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
kaf24@1127 110 {
kaf24@7250 111 struct evtchn *lchn, *rchn;
kaf24@7250 112 struct domain *ld = current->domain, *rd;
kaf24@7250 113 int lport, rport = bind->remote_port;
kaf24@7421 114 domid_t rdom = bind->remote_dom;
kaf24@1506 115 long rc = 0;
kaf24@954 116
kaf24@7421 117 if ( rdom == DOMID_SELF )
kaf24@7421 118 rdom = current->domain->domain_id;
kaf24@7421 119
kaf24@7421 120 if ( (rd = find_domain_by_id(rdom)) == NULL )
kaf24@1127 121 return -ESRCH;
kaf24@1127 122
kaf24@1127 123 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@7250 124 if ( ld < rd )
kaf24@954 125 {
kaf24@7250 126 spin_lock(&ld->evtchn_lock);
kaf24@7250 127 spin_lock(&rd->evtchn_lock);
kaf24@954 128 }
kaf24@954 129 else
kaf24@954 130 {
kaf24@7250 131 if ( ld != rd )
kaf24@7250 132 spin_lock(&rd->evtchn_lock);
kaf24@7250 133 spin_lock(&ld->evtchn_lock);
kaf24@954 134 }
kaf24@954 135
kaf24@7250 136 if ( (lport = get_free_port(ld)) < 0 )
kaf24@7250 137 ERROR_EXIT(lport);
kaf24@7250 138 lchn = evtchn_from_port(ld, lport);
kaf24@2713 139
kaf24@7250 140 if ( !port_is_valid(rd, rport) )
kaf24@2713 141 ERROR_EXIT(-EINVAL);
kaf24@7250 142 rchn = evtchn_from_port(rd, rport);
kaf24@7250 143 if ( (rchn->state != ECS_UNBOUND) ||
kaf24@7250 144 (rchn->u.unbound.remote_domid != ld->domain_id) )
kaf24@7250 145 ERROR_EXIT(-EINVAL);
kaf24@954 146
kaf24@7250 147 lchn->u.interdomain.remote_dom = rd;
kaf24@7250 148 lchn->u.interdomain.remote_port = (u16)rport;
kaf24@7250 149 lchn->state = ECS_INTERDOMAIN;
kaf24@7250 150
kaf24@7250 151 rchn->u.interdomain.remote_dom = ld;
kaf24@7250 152 rchn->u.interdomain.remote_port = (u16)lport;
kaf24@7250 153 rchn->state = ECS_INTERDOMAIN;
kaf24@954 154
kaf24@2713 155 /*
kaf24@7250 156 * We may have lost notifications on the remote unbound port. Fix that up
kaf24@7250 157 * here by conservatively always setting a notification on the local port.
kaf24@2713 158 */
kaf24@7250 159 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
kaf24@2713 160
kaf24@7250 161 bind->local_port = lport;
kaf24@1127 162
kaf24@954 163 out:
kaf24@7250 164 spin_unlock(&ld->evtchn_lock);
kaf24@7250 165 if ( ld != rd )
kaf24@7250 166 spin_unlock(&rd->evtchn_lock);
kaf24@1127 167
kaf24@7250 168 put_domain(rd);
kaf24@954 169
kaf24@954 170 return rc;
kaf24@954 171 }
kaf24@954 172
kaf24@954 173
kaf24@1218 174 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 175 {
kaf24@5308 176 struct evtchn *chn;
kaf24@7204 177 struct vcpu *v;
kaf24@7204 178 struct domain *d = current->domain;
kaf24@7250 179 int port, virq = bind->virq, vcpu = bind->vcpu;
kaf24@7250 180 long rc = 0;
kaf24@1218 181
kaf24@5289 182 if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
kaf24@1218 183 return -EINVAL;
kaf24@1218 184
kaf24@7250 185 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
kaf24@7204 186 return -ENOENT;
cl349@6680 187
kaf24@5308 188 spin_lock(&d->evtchn_lock);
kaf24@1218 189
kaf24@7250 190 if ( v->virq_to_evtchn[virq] != 0 )
kaf24@7250 191 ERROR_EXIT(-EEXIST);
kaf24@7250 192
kaf24@7250 193 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 194 ERROR_EXIT(port);
kaf24@1218 195
kaf24@5308 196 chn = evtchn_from_port(d, port);
kaf24@5308 197 chn->state = ECS_VIRQ;
kaf24@7250 198 chn->notify_vcpu_id = vcpu;
kaf24@5308 199 chn->u.virq = virq;
kaf24@1218 200
kaf24@7250 201 v->virq_to_evtchn[virq] = bind->port = port;
kaf24@1218 202
kaf24@1218 203 out:
kaf24@5308 204 spin_unlock(&d->evtchn_lock);
kaf24@1218 205
kaf24@7250 206 return rc;
cl349@2932 207 }
cl349@2932 208
kaf24@5308 209
cl349@2932 210 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 211 {
kaf24@5308 212 struct evtchn *chn;
kaf24@5308 213 struct domain *d = current->domain;
kaf24@7250 214 int port, vcpu = bind->vcpu;
kaf24@7250 215 long rc = 0;
kaf24@4202 216
kaf24@7250 217 if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
kaf24@7204 218 return -ENOENT;
kaf24@7204 219
kaf24@5308 220 spin_lock(&d->evtchn_lock);
cl349@2932 221
kaf24@7250 222 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 223 ERROR_EXIT(port);
cl349@2932 224
kaf24@7250 225 chn = evtchn_from_port(d, port);
kaf24@7250 226 chn->state = ECS_IPI;
kaf24@7250 227 chn->notify_vcpu_id = vcpu;
kaf24@7250 228
kaf24@7250 229 bind->port = port;
kaf24@7250 230
kaf24@7250 231 out:
kaf24@5308 232 spin_unlock(&d->evtchn_lock);
cl349@2932 233
kaf24@7250 234 return rc;
kaf24@1218 235 }
kaf24@1218 236
kaf24@1218 237
kaf24@1235 238 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 239 {
kaf24@5308 240 struct evtchn *chn;
cl349@2919 241 struct domain *d = current->domain;
kaf24@7250 242 int port, pirq = bind->pirq;
kaf24@7250 243 long rc;
kaf24@1235 244
kaf24@1506 245 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 246 return -EINVAL;
kaf24@1235 247
kaf24@8468 248 if ( !irq_access_permitted(d, pirq) )
kaf24@8468 249 return -EPERM;
kaf24@8468 250
kaf24@5308 251 spin_lock(&d->evtchn_lock);
kaf24@1235 252
kaf24@7250 253 if ( d->pirq_to_evtchn[pirq] != 0 )
kaf24@7250 254 ERROR_EXIT(-EEXIST);
kaf24@7250 255
kaf24@7250 256 if ( (port = get_free_port(d)) < 0 )
kaf24@7250 257 ERROR_EXIT(port);
kaf24@1235 258
kaf24@5308 259 chn = evtchn_from_port(d, port);
kaf24@5308 260
kaf24@1506 261 d->pirq_to_evtchn[pirq] = port;
sos22@5700 262 rc = pirq_guest_bind(d->vcpu[0], pirq,
kaf24@1253 263 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 264 if ( rc != 0 )
kaf24@1239 265 {
kaf24@1506 266 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 267 goto out;
kaf24@1239 268 }
kaf24@1239 269
kaf24@5308 270 chn->state = ECS_PIRQ;
kaf24@5308 271 chn->u.pirq = pirq;
kaf24@1235 272
kaf24@7250 273 bind->port = port;
kaf24@7250 274
kaf24@1235 275 out:
kaf24@5308 276 spin_unlock(&d->evtchn_lock);
kaf24@1235 277
kaf24@7250 278 return rc;
kaf24@1235 279 }
kaf24@1235 280
kaf24@1235 281
kaf24@1506 282 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 283 {
kaf24@5308 284 struct domain *d2 = NULL;
kaf24@5308 285 struct vcpu *v;
kaf24@5308 286 struct evtchn *chn1, *chn2;
kaf24@5308 287 int port2;
kaf24@5308 288 long rc = 0;
kaf24@954 289
kaf24@954 290 again:
kaf24@5308 291 spin_lock(&d1->evtchn_lock);
kaf24@954 292
kaf24@5308 293 if ( !port_is_valid(d1, port1) )
kaf24@954 294 {
kaf24@954 295 rc = -EINVAL;
kaf24@954 296 goto out;
kaf24@954 297 }
kaf24@954 298
kaf24@5308 299 chn1 = evtchn_from_port(d1, port1);
kaf24@5308 300 switch ( chn1->state )
kaf24@954 301 {
kaf24@1218 302 case ECS_FREE:
cl349@3297 303 case ECS_RESERVED:
kaf24@1218 304 rc = -EINVAL;
kaf24@1218 305 goto out;
kaf24@1218 306
kaf24@1218 307 case ECS_UNBOUND:
kaf24@1218 308 break;
kaf24@1218 309
kaf24@1218 310 case ECS_PIRQ:
kaf24@5308 311 if ( (rc = pirq_guest_unbind(d1, chn1->u.pirq)) == 0 )
kaf24@5308 312 d1->pirq_to_evtchn[chn1->u.pirq] = 0;
kaf24@1218 313 break;
kaf24@1218 314
kaf24@1218 315 case ECS_VIRQ:
kaf24@5289 316 for_each_vcpu ( d1, v )
kaf24@5308 317 if ( v->virq_to_evtchn[chn1->u.virq] == port1 )
kaf24@5308 318 v->virq_to_evtchn[chn1->u.virq] = 0;
kaf24@1218 319 break;
kaf24@1218 320
cl349@2932 321 case ECS_IPI:
cl349@2932 322 break;
cl349@2932 323
kaf24@1218 324 case ECS_INTERDOMAIN:
kaf24@1506 325 if ( d2 == NULL )
kaf24@954 326 {
kaf24@5308 327 d2 = chn1->u.interdomain.remote_dom;
kaf24@1505 328
kaf24@1506 329 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 330 if ( unlikely(!get_domain(d2)) )
kaf24@1505 331 {
kaf24@1505 332 /*
kaf24@1506 333 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 334 * and so will close this event channel for us.
kaf24@1505 335 */
kaf24@1506 336 d2 = NULL;
kaf24@1505 337 goto out;
kaf24@1505 338 }
kaf24@1127 339
kaf24@1542 340 if ( d1 < d2 )
kaf24@954 341 {
kaf24@5308 342 spin_lock(&d2->evtchn_lock);
kaf24@954 343 }
kaf24@1506 344 else if ( d1 != d2 )
kaf24@954 345 {
kaf24@5308 346 spin_unlock(&d1->evtchn_lock);
kaf24@5308 347 spin_lock(&d2->evtchn_lock);
kaf24@954 348 goto again;
kaf24@954 349 }
kaf24@954 350 }
kaf24@5308 351 else if ( d2 != chn1->u.interdomain.remote_dom )
kaf24@954 352 {
kaf24@8232 353 /*
kaf24@8232 354 * We can only get here if the port was closed and re-bound after
kaf24@8232 355 * unlocking d1 but before locking d2 above. We could retry but
kaf24@8232 356 * it is easier to return the same error as if we had seen the
kaf24@8232 357 * port in ECS_CLOSED. It must have passed through that state for
kaf24@8232 358 * us to end up here, so it's a valid error to return.
kaf24@8232 359 */
kaf24@8232 360 BUG_ON(d1 != current->domain);
kaf24@954 361 rc = -EINVAL;
kaf24@954 362 goto out;
kaf24@954 363 }
kaf24@9596 364
kaf24@5308 365 port2 = chn1->u.interdomain.remote_port;
kaf24@5308 366 BUG_ON(!port_is_valid(d2, port2));
kaf24@954 367
kaf24@5308 368 chn2 = evtchn_from_port(d2, port2);
kaf24@5308 369 BUG_ON(chn2->state != ECS_INTERDOMAIN);
kaf24@5308 370 BUG_ON(chn2->u.interdomain.remote_dom != d1);
kaf24@954 371
kaf24@5308 372 chn2->state = ECS_UNBOUND;
kaf24@5308 373 chn2->u.unbound.remote_domid = d1->domain_id;
kaf24@1218 374 break;
kaf24@1218 375
kaf24@1218 376 default:
kaf24@1218 377 BUG();
kaf24@954 378 }
kaf24@954 379
kaf24@5703 380 /* Reset binding to vcpu0 when the channel is freed. */
kaf24@5703 381 chn1->state = ECS_FREE;
kaf24@5703 382 chn1->notify_vcpu_id = 0;
kaf24@1133 383
kaf24@954 384 out:
kaf24@1506 385 if ( d2 != NULL )
kaf24@954 386 {
kaf24@1506 387 if ( d1 != d2 )
kaf24@5308 388 spin_unlock(&d2->evtchn_lock);
kaf24@1506 389 put_domain(d2);
kaf24@954 390 }
kaf24@954 391
kaf24@5308 392 spin_unlock(&d1->evtchn_lock);
kaf24@1145 393
kaf24@954 394 return rc;
kaf24@954 395 }
kaf24@954 396
kaf24@954 397
kaf24@1218 398 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 399 {
kaf24@7250 400 return __evtchn_close(current->domain, close->port);
kaf24@1127 401 }
kaf24@1127 402
kaf24@1127 403
kaf24@8970 404 long evtchn_send(unsigned int lport)
kaf24@954 405 {
kaf24@5308 406 struct evtchn *lchn, *rchn;
kaf24@5308 407 struct domain *ld = current->domain, *rd;
cl349@2937 408 int rport, ret = 0;
kaf24@954 409
kaf24@5308 410 spin_lock(&ld->evtchn_lock);
kaf24@954 411
kaf24@5308 412 if ( unlikely(!port_is_valid(ld, lport)) )
kaf24@954 413 {
kaf24@5308 414 spin_unlock(&ld->evtchn_lock);
kaf24@954 415 return -EINVAL;
kaf24@954 416 }
kaf24@954 417
kaf24@5308 418 lchn = evtchn_from_port(ld, lport);
kaf24@5308 419 switch ( lchn->state )
cl349@2937 420 {
cl349@2937 421 case ECS_INTERDOMAIN:
kaf24@5308 422 rd = lchn->u.interdomain.remote_dom;
kaf24@5308 423 rport = lchn->u.interdomain.remote_port;
kaf24@5308 424 rchn = evtchn_from_port(rd, rport);
kaf24@5308 425 evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
cl349@2937 426 break;
cl349@2937 427 case ECS_IPI:
kaf24@5308 428 evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
cl349@2937 429 break;
kaf24@7250 430 case ECS_UNBOUND:
kaf24@7250 431 /* silently drop the notification */
kaf24@7250 432 break;
cl349@2937 433 default:
cl349@2937 434 ret = -EINVAL;
cl349@2937 435 }
kaf24@954 436
kaf24@5308 437 spin_unlock(&ld->evtchn_lock);
kaf24@954 438
cl349@2937 439 return ret;
kaf24@954 440 }
kaf24@954 441
kaf24@9596 442
kaf24@9262 443 void evtchn_set_pending(struct vcpu *v, int port)
kaf24@9262 444 {
kaf24@9262 445 struct domain *d = v->domain;
kaf24@9262 446 shared_info_t *s = d->shared_info;
kaf24@9262 447
kaf24@9262 448 /*
kaf24@9262 449 * The following bit operations must happen in strict order.
kaf24@9262 450 * NB. On x86, the atomic bit operations also act as memory barriers.
kaf24@9262 451 * There is therefore sufficiently strict ordering for this architecture --
kaf24@9262 452 * others may require explicit memory barriers.
kaf24@9262 453 */
kaf24@9262 454
kaf24@9262 455 if ( test_and_set_bit(port, &s->evtchn_pending[0]) )
kaf24@9262 456 return;
kaf24@9262 457
kaf24@9262 458 if ( !test_bit (port, &s->evtchn_mask[0]) &&
kaf24@9262 459 !test_and_set_bit(port / BITS_PER_LONG,
kaf24@9262 460 &v->vcpu_info->evtchn_pending_sel) &&
kaf24@9262 461 !test_and_set_bit(0, &v->vcpu_info->evtchn_upcall_pending) )
kaf24@9262 462 {
kaf24@9262 463 evtchn_notify(v);
kaf24@9262 464 }
kaf24@9262 465 else if ( unlikely(test_bit(_VCPUF_blocked, &v->vcpu_flags) &&
kaf24@9262 466 v->vcpu_info->evtchn_upcall_mask) )
kaf24@9262 467 {
kaf24@9262 468 /*
kaf24@9262 469 * Blocked and masked will usually mean that the VCPU executed
kaf24@9262 470 * SCHEDOP_poll. Kick the VCPU in case this port is in its poll list.
kaf24@9262 471 */
kaf24@9262 472 vcpu_unblock(v);
kaf24@9262 473 }
kaf24@9262 474 }
kaf24@9262 475
kaf24@9596 476
kaf24@9262 477 void send_guest_virq(struct vcpu *v, int virq)
kaf24@9262 478 {
kaf24@9262 479 int port = v->virq_to_evtchn[virq];
kaf24@9262 480
kaf24@9262 481 if ( likely(port != 0) )
kaf24@9262 482 evtchn_set_pending(v, port);
kaf24@9262 483 }
kaf24@9262 484
kaf24@9596 485
kaf24@5308 486 void send_guest_pirq(struct domain *d, int pirq)
kaf24@5308 487 {
kaf24@5308 488 int port = d->pirq_to_evtchn[pirq];
kaf24@5308 489 struct evtchn *chn = evtchn_from_port(d, port);
kaf24@5308 490 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
kaf24@5308 491 }
kaf24@954 492
kaf24@9596 493
kaf24@1218 494 static long evtchn_status(evtchn_status_t *status)
kaf24@954 495 {
kaf24@1506 496 struct domain *d;
kaf24@1506 497 domid_t dom = status->dom;
kaf24@1506 498 int port = status->port;
kaf24@5308 499 struct evtchn *chn;
kaf24@1506 500 long rc = 0;
kaf24@1127 501
kaf24@1129 502 if ( dom == DOMID_SELF )
kaf24@4877 503 dom = current->domain->domain_id;
cl349@2919 504 else if ( !IS_PRIV(current->domain) )
kaf24@1127 505 return -EPERM;
kaf24@1127 506
kaf24@1506 507 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 508 return -ESRCH;
kaf24@954 509
kaf24@5308 510 spin_lock(&d->evtchn_lock);
kaf24@954 511
kaf24@5308 512 if ( !port_is_valid(d, port) )
kaf24@954 513 {
kaf24@1266 514 rc = -EINVAL;
kaf24@1266 515 goto out;
kaf24@1127 516 }
kaf24@1127 517
kaf24@5308 518 chn = evtchn_from_port(d, port);
kaf24@5308 519 switch ( chn->state )
kaf24@1127 520 {
kaf24@1127 521 case ECS_FREE:
cl349@3297 522 case ECS_RESERVED:
kaf24@1127 523 status->status = EVTCHNSTAT_closed;
kaf24@1127 524 break;
kaf24@1218 525 case ECS_UNBOUND:
kaf24@1218 526 status->status = EVTCHNSTAT_unbound;
kaf24@5308 527 status->u.unbound.dom = chn->u.unbound.remote_domid;
kaf24@1127 528 break;
kaf24@1218 529 case ECS_INTERDOMAIN:
kaf24@1218 530 status->status = EVTCHNSTAT_interdomain;
cl349@2924 531 status->u.interdomain.dom =
kaf24@5308 532 chn->u.interdomain.remote_dom->domain_id;
kaf24@5308 533 status->u.interdomain.port = chn->u.interdomain.remote_port;
kaf24@1218 534 break;
kaf24@1218 535 case ECS_PIRQ:
kaf24@1218 536 status->status = EVTCHNSTAT_pirq;
kaf24@5308 537 status->u.pirq = chn->u.pirq;
kaf24@1218 538 break;
kaf24@1218 539 case ECS_VIRQ:
kaf24@1218 540 status->status = EVTCHNSTAT_virq;
kaf24@5308 541 status->u.virq = chn->u.virq;
kaf24@1127 542 break;
cl349@2932 543 case ECS_IPI:
kaf24@5703 544 status->status = EVTCHNSTAT_ipi;
cl349@2932 545 break;
kaf24@1127 546 default:
kaf24@1127 547 BUG();
kaf24@954 548 }
kaf24@954 549
kaf24@5703 550 status->vcpu = chn->notify_vcpu_id;
kaf24@5703 551
kaf24@1266 552 out:
kaf24@5308 553 spin_unlock(&d->evtchn_lock);
kaf24@1506 554 put_domain(d);
kaf24@1266 555 return rc;
kaf24@954 556 }
kaf24@954 557
kaf24@9596 558
kaf24@8970 559 long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id)
iap10@5691 560 {
kaf24@8970 561 struct domain *d = current->domain;
iap10@5691 562 struct evtchn *chn;
kaf24@5703 563 long rc = 0;
kaf24@5703 564
kaf24@8970 565 if ( (vcpu_id >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu_id] == NULL) )
kaf24@7250 566 return -ENOENT;
iap10@5691 567
iap10@5691 568 spin_lock(&d->evtchn_lock);
iap10@5691 569
iap10@5691 570 if ( !port_is_valid(d, port) )
iap10@5691 571 {
iap10@5691 572 rc = -EINVAL;
iap10@5691 573 goto out;
iap10@5691 574 }
iap10@5691 575
iap10@5691 576 chn = evtchn_from_port(d, port);
kaf24@5703 577 switch ( chn->state )
kaf24@5703 578 {
kaf24@5703 579 case ECS_UNBOUND:
kaf24@5703 580 case ECS_INTERDOMAIN:
kaf24@5703 581 case ECS_PIRQ:
kaf24@8970 582 chn->notify_vcpu_id = vcpu_id;
kaf24@5703 583 break;
kaf24@5703 584 default:
kaf24@5703 585 rc = -EINVAL;
kaf24@5703 586 break;
kaf24@5703 587 }
iap10@5691 588
iap10@5691 589 out:
iap10@5691 590 spin_unlock(&d->evtchn_lock);
iap10@5691 591 return rc;
iap10@5691 592 }
kaf24@954 593
kaf24@9596 594
kaf24@8351 595 static long evtchn_unmask(evtchn_unmask_t *unmask)
kaf24@8351 596 {
kaf24@8351 597 struct domain *d = current->domain;
kaf24@8351 598 shared_info_t *s = d->shared_info;
kaf24@8351 599 int port = unmask->port;
kaf24@8351 600 struct vcpu *v;
kaf24@8351 601
kaf24@8351 602 spin_lock(&d->evtchn_lock);
kaf24@8351 603
kaf24@8351 604 if ( unlikely(!port_is_valid(d, port)) )
kaf24@8351 605 {
kaf24@8351 606 spin_unlock(&d->evtchn_lock);
kaf24@8351 607 return -EINVAL;
kaf24@8351 608 }
kaf24@8351 609
kaf24@8351 610 v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
kaf24@8351 611
kaf24@8351 612 /*
kaf24@8351 613 * These operations must happen in strict order. Based on
kaf24@8351 614 * include/xen/event.h:evtchn_set_pending().
kaf24@8351 615 */
kaf24@8351 616 if ( test_and_clear_bit(port, &s->evtchn_mask[0]) &&
kaf24@8351 617 test_bit (port, &s->evtchn_pending[0]) &&
kaf24@8351 618 !test_and_set_bit (port / BITS_PER_LONG,
kaf24@8351 619 &v->vcpu_info->evtchn_pending_sel) &&
kaf24@8351 620 !test_and_set_bit (0, &v->vcpu_info->evtchn_upcall_pending) )
kaf24@8351 621 {
kaf24@8351 622 evtchn_notify(v);
kaf24@8351 623 }
kaf24@8351 624
kaf24@8351 625 spin_unlock(&d->evtchn_lock);
kaf24@8351 626
kaf24@8351 627 return 0;
kaf24@8351 628 }
kaf24@8351 629
kaf24@9596 630
kaf24@9183 631 long do_event_channel_op(GUEST_HANDLE(evtchn_op_t) uop)
kaf24@954 632 {
kaf24@954 633 long rc;
kaf24@8679 634 struct evtchn_op op;
kaf24@954 635
kaf24@9183 636 if ( copy_from_guest(&op, uop, 1) != 0 )
kaf24@1127 637 return -EFAULT;
kaf24@1127 638
smh22@5514 639 if (acm_pre_event_channel(&op))
smh22@5514 640 return -EACCES;
smh22@5514 641
kaf24@1127 642 switch ( op.cmd )
kaf24@954 643 {
kaf24@2713 644 case EVTCHNOP_alloc_unbound:
kaf24@2713 645 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@9183 646 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
kaf24@2713 647 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 648 break;
kaf24@2713 649
kaf24@1218 650 case EVTCHNOP_bind_interdomain:
kaf24@1218 651 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@9183 652 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
kaf24@1218 653 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 654 break;
kaf24@1218 655
kaf24@1218 656 case EVTCHNOP_bind_virq:
kaf24@1218 657 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@9183 658 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
kaf24@1235 659 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 660 break;
kaf24@1235 661
cl349@2932 662 case EVTCHNOP_bind_ipi:
cl349@2932 663 rc = evtchn_bind_ipi(&op.u.bind_ipi);
kaf24@9183 664 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
cl349@2932 665 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 666 break;
cl349@2932 667
kaf24@1235 668 case EVTCHNOP_bind_pirq:
kaf24@1235 669 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@9183 670 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
kaf24@1127 671 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 672 break;
kaf24@954 673
kaf24@954 674 case EVTCHNOP_close:
kaf24@1218 675 rc = evtchn_close(&op.u.close);
kaf24@954 676 break;
kaf24@954 677
kaf24@954 678 case EVTCHNOP_send:
kaf24@7250 679 rc = evtchn_send(op.u.send.port);
kaf24@954 680 break;
kaf24@954 681
kaf24@954 682 case EVTCHNOP_status:
kaf24@1218 683 rc = evtchn_status(&op.u.status);
kaf24@9183 684 if ( (rc == 0) && (copy_to_guest(uop, &op, 1) != 0) )
kaf24@1127 685 rc = -EFAULT;
kaf24@954 686 break;
kaf24@954 687
kaf24@5703 688 case EVTCHNOP_bind_vcpu:
kaf24@8970 689 rc = evtchn_bind_vcpu(op.u.bind_vcpu.port, op.u.bind_vcpu.vcpu);
iap10@5691 690 break;
iap10@5691 691
kaf24@8351 692 case EVTCHNOP_unmask:
kaf24@8351 693 rc = evtchn_unmask(&op.u.unmask);
kaf24@8351 694 break;
kaf24@8351 695
kaf24@954 696 default:
kaf24@954 697 rc = -ENOSYS;
kaf24@954 698 break;
kaf24@954 699 }
kaf24@954 700
kaf24@954 701 return rc;
kaf24@954 702 }
kaf24@954 703
kaf24@954 704
kaf24@9596 705 int evtchn_open_reserved_port(struct domain *d)
kaf24@9596 706 {
kaf24@9596 707 struct evtchn *chn;
kaf24@9596 708 int port;
kaf24@9596 709
kaf24@9596 710 spin_lock(&d->evtchn_lock);
kaf24@9596 711
kaf24@9596 712 if ( (port = get_free_port(d)) >= 0 )
kaf24@9596 713 {
kaf24@9596 714 chn = evtchn_from_port(d, port);
kaf24@9596 715 chn->state = ECS_RESERVED;
kaf24@9596 716 }
kaf24@9596 717
kaf24@9596 718 spin_unlock(&d->evtchn_lock);
kaf24@9596 719
kaf24@9596 720 return port;
kaf24@9596 721 }
kaf24@9596 722
kaf24@9596 723
kaf24@9596 724 void evtchn_close_reserved_port(struct domain *d, int port)
kaf24@9596 725 {
kaf24@9596 726 struct evtchn *chn;
kaf24@9596 727
kaf24@9596 728 spin_lock(&d->evtchn_lock);
kaf24@9596 729
kaf24@9596 730 BUG_ON(!port_is_valid(d, port));
kaf24@9596 731
kaf24@9596 732 chn = evtchn_from_port(d, port);
kaf24@9596 733 chn->state = ECS_FREE;
kaf24@9596 734 chn->notify_vcpu_id = 0;
kaf24@9596 735
kaf24@9596 736 spin_unlock(&d->evtchn_lock);
kaf24@9596 737 }
kaf24@9596 738
kaf24@9596 739
kaf24@9596 740 void evtchn_notify_reserved_port(struct domain *d, int port)
kaf24@9596 741 {
kaf24@9596 742 struct evtchn *chn = evtchn_from_port(d, port);
kaf24@9596 743 evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
kaf24@9596 744 }
kaf24@9596 745
kaf24@9596 746
kaf24@5308 747 int evtchn_init(struct domain *d)
kaf24@1218 748 {
kaf24@5308 749 spin_lock_init(&d->evtchn_lock);
kaf24@5308 750 if ( get_free_port(d) != 0 )
cl349@3291 751 return -EINVAL;
kaf24@5308 752 evtchn_from_port(d, 0)->state = ECS_RESERVED;
cl349@3291 753 return 0;
kaf24@1218 754 }
kaf24@1218 755
kaf24@1218 756
kaf24@5308 757 void evtchn_destroy(struct domain *d)
kaf24@954 758 {
kaf24@954 759 int i;
kaf24@5308 760
kaf24@5308 761 for ( i = 0; port_is_valid(d, i); i++ )
kaf24@1506 762 (void)__evtchn_close(d, i);
kaf24@5308 763
kaf24@5308 764 for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
kaf24@7782 765 xfree(d->evtchn[i]);
kaf24@954 766 }
kaf24@3914 767
kaf24@3914 768 /*
kaf24@3914 769 * Local variables:
kaf24@3914 770 * mode: C
kaf24@3914 771 * c-set-style: "BSD"
kaf24@3914 772 * c-basic-offset: 4
kaf24@3914 773 * tab-width: 4
kaf24@3914 774 * indent-tabs-mode: nil
kaf24@3988 775 * End:
kaf24@3914 776 */