ia64/xen-unstable

annotate xen/common/event_channel.c @ 8468:d966b7a00959

Allow non-privileged domains restricted access to
I/O memory and physical interrupts, under control
of domain0. Capabilities are maintained as rangesets
in Xen.

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