ia64/xen-unstable

annotate xen/common/event_channel.c @ 9776:72f9c751d3ea

Replace &foo[0] with foo where the latter seems cleaner
(which is usually, and particularly when its an argument
to one of the bitops functions).

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