ia64/xen-unstable

annotate xen/common/event_channel.c @ 7250:37bea65ed6ca

Big simplification of the Xen event-channel interface.
EVTCHNOP_bind_interdomain in particular is much simpler.

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