ia64/xen-unstable

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