ia64/xen-unstable

annotate xen/common/event_channel.c @ 7782:fcb7e5616102

Remove unnecessary NULL checks before freeing memory blocks.
The following functions check for NULL internally:
free, kfree, xfree, free_xenheap_page[s]

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