ia64/xen-unstable

annotate xen/common/event_channel.c @ 2717:fa8f7b78d2c9

bitkeeper revision 1.1159.130.4 (41792f48shx1E0y1gWtmTdYNJN6Q7g)

Put check in the wrong place. :-)
author kaf24@freefall.cl.cam.ac.uk
date Fri Oct 22 16:03:20 2004 +0000 (2004-10-22)
parents 636399a0f740
children bd93b9d866a5
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>
kaf24@954 25
kaf24@1127 26 #include <hypervisor-ifs/hypervisor-if.h>
kaf24@1127 27 #include <hypervisor-ifs/event_channel.h>
kaf24@1127 28
kaf24@1218 29 #define INIT_EVENT_CHANNELS 16
kaf24@1218 30 #define MAX_EVENT_CHANNELS 1024
kaf24@954 31
kaf24@2713 32
kaf24@1506 33 static int get_free_port(struct domain *d)
kaf24@954 34 {
kaf24@1127 35 int max, port;
kaf24@1127 36 event_channel_t *chn;
kaf24@1127 37
kaf24@1506 38 max = d->max_event_channel;
kaf24@1506 39 chn = d->event_channel;
kaf24@1127 40
kaf24@1127 41 for ( port = 0; port < max; port++ )
kaf24@1127 42 if ( chn[port].state == ECS_FREE )
kaf24@1127 43 break;
kaf24@1127 44
kaf24@1127 45 if ( port == max )
kaf24@1127 46 {
kaf24@1127 47 if ( max == MAX_EVENT_CHANNELS )
kaf24@1127 48 return -ENOSPC;
kaf24@1127 49
kaf24@1258 50 max *= 2;
kaf24@1127 51
kaf24@1920 52 chn = xmalloc(max * sizeof(event_channel_t));
kaf24@1127 53 if ( unlikely(chn == NULL) )
kaf24@1127 54 return -ENOMEM;
kaf24@1127 55
kaf24@1127 56 memset(chn, 0, max * sizeof(event_channel_t));
kaf24@1127 57
kaf24@1506 58 if ( d->event_channel != NULL )
kaf24@1127 59 {
kaf24@1506 60 memcpy(chn, d->event_channel, (max/2) * sizeof(event_channel_t));
kaf24@1920 61 xfree(d->event_channel);
kaf24@1127 62 }
kaf24@1127 63
kaf24@1506 64 d->event_channel = chn;
kaf24@1506 65 d->max_event_channel = max;
kaf24@1127 66 }
kaf24@1127 67
kaf24@1127 68 return port;
kaf24@1127 69 }
kaf24@1127 70
kaf24@2713 71
kaf24@2713 72 static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
kaf24@2713 73 {
kaf24@2713 74 struct domain *d = current;
kaf24@2713 75 int port;
kaf24@2713 76
kaf24@2713 77 spin_lock(&d->event_channel_lock);
kaf24@2713 78
kaf24@2713 79 if ( (port = get_free_port(d)) >= 0 )
kaf24@2713 80 {
kaf24@2713 81 d->event_channel[port].state = ECS_UNBOUND;
kaf24@2713 82 d->event_channel[port].u.unbound.remote_domid = alloc->dom;
kaf24@2713 83 }
kaf24@2713 84
kaf24@2713 85 spin_unlock(&d->event_channel_lock);
kaf24@2713 86
kaf24@2713 87 if ( port < 0 )
kaf24@2713 88 return port;
kaf24@2713 89
kaf24@2713 90 alloc->port = port;
kaf24@2713 91 return 0;
kaf24@2713 92 }
kaf24@2713 93
kaf24@2713 94
kaf24@1218 95 static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
kaf24@1127 96 {
kaf24@2713 97 #define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
kaf24@1506 98 struct domain *d1, *d2;
kaf24@2713 99 int port1 = bind->port1, port2 = bind->port2;
kaf24@1506 100 domid_t dom1 = bind->dom1, dom2 = bind->dom2;
kaf24@1506 101 long rc = 0;
kaf24@954 102
kaf24@2713 103 if ( !IS_PRIV(current) && (dom1 != DOMID_SELF) )
kaf24@1127 104 return -EPERM;
kaf24@954 105
kaf24@2713 106 if ( (port1 < 0) || (port2 < 0) )
kaf24@2713 107 return -EINVAL;
kaf24@2713 108
kaf24@1129 109 if ( dom1 == DOMID_SELF )
kaf24@2710 110 dom1 = current->id;
kaf24@1129 111 if ( dom2 == DOMID_SELF )
kaf24@2710 112 dom2 = current->id;
kaf24@1127 113
kaf24@1506 114 if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
kaf24@1506 115 ((d2 = find_domain_by_id(dom2)) == NULL) )
kaf24@1127 116 {
kaf24@1506 117 if ( d1 != NULL )
kaf24@1506 118 put_domain(d1);
kaf24@1127 119 return -ESRCH;
kaf24@1127 120 }
kaf24@1127 121
kaf24@1127 122 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@1542 123 if ( d1 < d2 )
kaf24@954 124 {
kaf24@1506 125 spin_lock(&d1->event_channel_lock);
kaf24@1506 126 spin_lock(&d2->event_channel_lock);
kaf24@954 127 }
kaf24@954 128 else
kaf24@954 129 {
kaf24@1506 130 if ( d1 != d2 )
kaf24@1506 131 spin_lock(&d2->event_channel_lock);
kaf24@1506 132 spin_lock(&d1->event_channel_lock);
kaf24@954 133 }
kaf24@954 134
kaf24@2713 135 /* Obtain, or ensure that we already have, a valid <port1>. */
kaf24@2713 136 if ( port1 == 0 )
kaf24@954 137 {
kaf24@2713 138 if ( (port1 = get_free_port(d1)) < 0 )
kaf24@2713 139 ERROR_EXIT(port1);
kaf24@2713 140 }
kaf24@2713 141 else if ( port1 >= d1->max_event_channel )
kaf24@2713 142 ERROR_EXIT(-EINVAL);
kaf24@2713 143
kaf24@2713 144 /* Obtain, or ensure that we already have, a valid <port2>. */
kaf24@2713 145 if ( port2 == 0 )
kaf24@2713 146 {
kaf24@2713 147 /* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
kaf24@2713 148 u16 tmp = d1->event_channel[port1].state;
kaf24@2713 149 d1->event_channel[port1].state = ECS_INTERDOMAIN;
kaf24@2713 150 port2 = get_free_port(d2);
kaf24@2713 151 d1->event_channel[port1].state = tmp;
kaf24@2713 152 if ( port2 < 0 )
kaf24@2713 153 ERROR_EXIT(port2);
kaf24@2713 154 }
kaf24@2713 155 else if ( port2 >= d2->max_event_channel )
kaf24@2713 156 ERROR_EXIT(-EINVAL);
kaf24@2713 157
kaf24@2713 158 /* Validate <dom1,port1>'s current state. */
kaf24@2713 159 switch ( d1->event_channel[port1].state )
kaf24@2713 160 {
kaf24@2713 161 case ECS_FREE:
kaf24@2713 162 break;
kaf24@2713 163
kaf24@2713 164 case ECS_UNBOUND:
kaf24@2713 165 if ( d1->event_channel[port1].u.unbound.remote_domid != dom2 )
kaf24@2713 166 ERROR_EXIT(-EINVAL);
kaf24@2713 167 break;
kaf24@2713 168
kaf24@2713 169 case ECS_INTERDOMAIN:
kaf24@2713 170 rc = ((d1->event_channel[port1].u.interdomain.remote_dom != d2) ||
kaf24@2713 171 (d1->event_channel[port1].u.interdomain.remote_port != port2)) ?
kaf24@2713 172 -EINVAL : 0;
kaf24@1127 173 goto out;
kaf24@2713 174
kaf24@2713 175 default:
kaf24@2713 176 ERROR_EXIT(-EINVAL);
kaf24@954 177 }
kaf24@954 178
kaf24@2713 179 /* Validate <dom2,port2>'s current state. */
kaf24@2713 180 switch ( d2->event_channel[port2].state )
kaf24@2713 181 {
kaf24@2713 182 case ECS_FREE:
kaf24@2717 183 if ( !IS_PRIV(current) && (dom2 != DOMID_SELF) )
kaf24@2717 184 ERROR_EXIT(-EPERM);
kaf24@2713 185 break;
kaf24@1329 186
kaf24@2713 187 case ECS_UNBOUND:
kaf24@2713 188 if ( d2->event_channel[port2].u.unbound.remote_domid != dom1 )
kaf24@2713 189 ERROR_EXIT(-EINVAL);
kaf24@2713 190 break;
kaf24@2713 191
kaf24@2713 192 default:
kaf24@2713 193 ERROR_EXIT(-EINVAL);
kaf24@1127 194 }
kaf24@954 195
kaf24@2713 196 /*
kaf24@2713 197 * Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
kaf24@2713 198 */
kaf24@2713 199
kaf24@2710 200 d1->event_channel[port1].u.interdomain.remote_dom = d2;
kaf24@2710 201 d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
kaf24@2713 202 d1->event_channel[port1].state = ECS_INTERDOMAIN;
kaf24@2713 203
kaf24@2710 204 d2->event_channel[port2].u.interdomain.remote_dom = d1;
kaf24@2710 205 d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
kaf24@2710 206 d2->event_channel[port2].state = ECS_INTERDOMAIN;
kaf24@1127 207
kaf24@954 208 out:
kaf24@1506 209 spin_unlock(&d1->event_channel_lock);
kaf24@1506 210 if ( d1 != d2 )
kaf24@1506 211 spin_unlock(&d2->event_channel_lock);
kaf24@1127 212
kaf24@1506 213 put_domain(d1);
kaf24@1506 214 put_domain(d2);
kaf24@1127 215
kaf24@1218 216 bind->port1 = port1;
kaf24@1218 217 bind->port2 = port2;
kaf24@954 218
kaf24@954 219 return rc;
kaf24@2713 220 #undef ERROR_EXIT
kaf24@954 221 }
kaf24@954 222
kaf24@954 223
kaf24@1218 224 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 225 {
kaf24@1506 226 struct domain *d = current;
kaf24@1506 227 int port, virq = bind->virq;
kaf24@1218 228
kaf24@1506 229 if ( virq >= ARRAY_SIZE(d->virq_to_evtchn) )
kaf24@1218 230 return -EINVAL;
kaf24@1218 231
kaf24@1506 232 spin_lock(&d->event_channel_lock);
kaf24@1218 233
kaf24@1218 234 /*
kaf24@1218 235 * Port 0 is the fallback port for VIRQs that haven't been explicitly
kaf24@1249 236 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 237 * bound to port 0.
kaf24@1218 238 */
kaf24@1506 239 if ( ((port = d->virq_to_evtchn[virq]) != 0) ||
kaf24@1249 240 (virq == VIRQ_MISDIRECT) ||
kaf24@1506 241 ((port = get_free_port(d)) < 0) )
kaf24@1218 242 goto out;
kaf24@1218 243
kaf24@1506 244 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 245 d->event_channel[port].u.virq = virq;
kaf24@1218 246
kaf24@1506 247 d->virq_to_evtchn[virq] = port;
kaf24@1218 248
kaf24@1218 249 out:
kaf24@1506 250 spin_unlock(&d->event_channel_lock);
kaf24@1218 251
kaf24@1218 252 if ( port < 0 )
kaf24@1218 253 return port;
kaf24@1218 254
kaf24@1218 255 bind->port = port;
kaf24@1218 256 return 0;
kaf24@1218 257 }
kaf24@1218 258
kaf24@1218 259
kaf24@1235 260 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 261 {
kaf24@1506 262 struct domain *d = current;
kaf24@1506 263 int port, rc, pirq = bind->pirq;
kaf24@1235 264
kaf24@1506 265 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 266 return -EINVAL;
kaf24@1235 267
kaf24@1506 268 spin_lock(&d->event_channel_lock);
kaf24@1235 269
kaf24@1506 270 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
kaf24@1506 271 ((rc = port = get_free_port(d)) < 0) )
kaf24@1235 272 goto out;
kaf24@1235 273
kaf24@1506 274 d->pirq_to_evtchn[pirq] = port;
kaf24@1506 275 rc = pirq_guest_bind(d, pirq,
kaf24@1253 276 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 277 if ( rc != 0 )
kaf24@1239 278 {
kaf24@1506 279 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 280 goto out;
kaf24@1239 281 }
kaf24@1239 282
kaf24@1506 283 d->event_channel[port].state = ECS_PIRQ;
kaf24@1506 284 d->event_channel[port].u.pirq = pirq;
kaf24@1235 285
kaf24@1235 286 out:
kaf24@1506 287 spin_unlock(&d->event_channel_lock);
kaf24@1235 288
kaf24@1239 289 if ( rc < 0 )
kaf24@1239 290 return rc;
kaf24@1235 291
kaf24@1235 292 bind->port = port;
kaf24@1235 293 return 0;
kaf24@1235 294 }
kaf24@1235 295
kaf24@1235 296
kaf24@1506 297 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 298 {
kaf24@1506 299 struct domain *d2 = NULL;
kaf24@1506 300 event_channel_t *chn1, *chn2;
kaf24@1506 301 int port2;
kaf24@1506 302 long rc = 0;
kaf24@954 303
kaf24@954 304 again:
kaf24@1506 305 spin_lock(&d1->event_channel_lock);
kaf24@954 306
kaf24@1506 307 chn1 = d1->event_channel;
kaf24@954 308
kaf24@1249 309 /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
kaf24@1506 310 if ( (port1 <= 0) || (port1 >= d1->max_event_channel) )
kaf24@954 311 {
kaf24@954 312 rc = -EINVAL;
kaf24@954 313 goto out;
kaf24@954 314 }
kaf24@954 315
kaf24@1218 316 switch ( chn1[port1].state )
kaf24@954 317 {
kaf24@1218 318 case ECS_FREE:
kaf24@1218 319 rc = -EINVAL;
kaf24@1218 320 goto out;
kaf24@1218 321
kaf24@1218 322 case ECS_UNBOUND:
kaf24@1218 323 break;
kaf24@1218 324
kaf24@1218 325 case ECS_PIRQ:
kaf24@1506 326 if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
kaf24@1506 327 d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
kaf24@1218 328 break;
kaf24@1218 329
kaf24@1218 330 case ECS_VIRQ:
kaf24@1506 331 d1->virq_to_evtchn[chn1[port1].u.virq] = 0;
kaf24@1218 332 break;
kaf24@1218 333
kaf24@1218 334 case ECS_INTERDOMAIN:
kaf24@1506 335 if ( d2 == NULL )
kaf24@954 336 {
kaf24@2710 337 d2 = chn1[port1].u.interdomain.remote_dom;
kaf24@1505 338
kaf24@1506 339 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 340 if ( unlikely(!get_domain(d2)) )
kaf24@1505 341 {
kaf24@1505 342 /*
kaf24@1506 343 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 344 * and so will close this event channel for us.
kaf24@1505 345 */
kaf24@1506 346 d2 = NULL;
kaf24@1505 347 goto out;
kaf24@1505 348 }
kaf24@1127 349
kaf24@1542 350 if ( d1 < d2 )
kaf24@954 351 {
kaf24@1506 352 spin_lock(&d2->event_channel_lock);
kaf24@954 353 }
kaf24@1506 354 else if ( d1 != d2 )
kaf24@954 355 {
kaf24@1506 356 spin_unlock(&d1->event_channel_lock);
kaf24@1506 357 spin_lock(&d2->event_channel_lock);
kaf24@954 358 goto again;
kaf24@954 359 }
kaf24@954 360 }
kaf24@2710 361 else if ( d2 != chn1[port1].u.interdomain.remote_dom )
kaf24@954 362 {
kaf24@954 363 rc = -EINVAL;
kaf24@954 364 goto out;
kaf24@954 365 }
kaf24@1505 366
kaf24@1506 367 chn2 = d2->event_channel;
kaf24@2710 368 port2 = chn1[port1].u.interdomain.remote_port;
kaf24@954 369
kaf24@1506 370 if ( port2 >= d2->max_event_channel )
kaf24@1127 371 BUG();
kaf24@1218 372 if ( chn2[port2].state != ECS_INTERDOMAIN )
kaf24@1127 373 BUG();
kaf24@2710 374 if ( chn2[port2].u.interdomain.remote_dom != d1 )
kaf24@1127 375 BUG();
kaf24@954 376
kaf24@1258 377 chn2[port2].state = ECS_UNBOUND;
kaf24@2713 378 chn2[port2].u.unbound.remote_domid = d1->id;
kaf24@1218 379 break;
kaf24@1218 380
kaf24@1218 381 default:
kaf24@1218 382 BUG();
kaf24@954 383 }
kaf24@954 384
kaf24@1258 385 chn1[port1].state = ECS_FREE;
kaf24@1133 386
kaf24@954 387 out:
kaf24@1506 388 if ( d2 != NULL )
kaf24@954 389 {
kaf24@1506 390 if ( d1 != d2 )
kaf24@1506 391 spin_unlock(&d2->event_channel_lock);
kaf24@1506 392 put_domain(d2);
kaf24@954 393 }
kaf24@954 394
kaf24@1506 395 spin_unlock(&d1->event_channel_lock);
kaf24@1145 396
kaf24@954 397 return rc;
kaf24@954 398 }
kaf24@954 399
kaf24@954 400
kaf24@1218 401 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 402 {
kaf24@1506 403 struct domain *d;
kaf24@1506 404 long rc;
kaf24@1506 405 domid_t dom = close->dom;
kaf24@1127 406
kaf24@1129 407 if ( dom == DOMID_SELF )
kaf24@2710 408 dom = current->id;
kaf24@1127 409 else if ( !IS_PRIV(current) )
kaf24@1127 410 return -EPERM;
kaf24@1127 411
kaf24@1506 412 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 413 return -ESRCH;
kaf24@1127 414
kaf24@1506 415 rc = __evtchn_close(d, close->port);
kaf24@1127 416
kaf24@1506 417 put_domain(d);
kaf24@1127 418 return rc;
kaf24@1127 419 }
kaf24@1127 420
kaf24@1127 421
kaf24@1218 422 static long evtchn_send(int lport)
kaf24@954 423 {
kaf24@1506 424 struct domain *ld = current, *rd;
kaf24@1506 425 int rport;
kaf24@954 426
kaf24@1506 427 spin_lock(&ld->event_channel_lock);
kaf24@954 428
kaf24@1127 429 if ( unlikely(lport < 0) ||
kaf24@1506 430 unlikely(lport >= ld->max_event_channel) ||
kaf24@1506 431 unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
kaf24@954 432 {
kaf24@1506 433 spin_unlock(&ld->event_channel_lock);
kaf24@954 434 return -EINVAL;
kaf24@954 435 }
kaf24@954 436
kaf24@2710 437 rd = ld->event_channel[lport].u.interdomain.remote_dom;
kaf24@2710 438 rport = ld->event_channel[lport].u.interdomain.remote_port;
kaf24@1127 439
kaf24@1506 440 evtchn_set_pending(rd, rport);
kaf24@954 441
kaf24@1506 442 spin_unlock(&ld->event_channel_lock);
kaf24@954 443
kaf24@954 444 return 0;
kaf24@954 445 }
kaf24@954 446
kaf24@954 447
kaf24@1218 448 static long evtchn_status(evtchn_status_t *status)
kaf24@954 449 {
kaf24@1506 450 struct domain *d;
kaf24@1506 451 domid_t dom = status->dom;
kaf24@1506 452 int port = status->port;
kaf24@1506 453 event_channel_t *chn;
kaf24@1506 454 long rc = 0;
kaf24@1127 455
kaf24@1129 456 if ( dom == DOMID_SELF )
kaf24@2710 457 dom = current->id;
kaf24@1127 458 else if ( !IS_PRIV(current) )
kaf24@1127 459 return -EPERM;
kaf24@1127 460
kaf24@1506 461 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 462 return -ESRCH;
kaf24@954 463
kaf24@1506 464 spin_lock(&d->event_channel_lock);
kaf24@954 465
kaf24@1506 466 chn = d->event_channel;
kaf24@954 467
kaf24@1506 468 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 469 {
kaf24@1266 470 rc = -EINVAL;
kaf24@1266 471 goto out;
kaf24@1127 472 }
kaf24@1127 473
kaf24@1129 474 switch ( chn[port].state )
kaf24@1127 475 {
kaf24@1127 476 case ECS_FREE:
kaf24@1127 477 status->status = EVTCHNSTAT_closed;
kaf24@1127 478 break;
kaf24@1218 479 case ECS_UNBOUND:
kaf24@1218 480 status->status = EVTCHNSTAT_unbound;
kaf24@2713 481 status->u.unbound.dom = chn[port].u.unbound.remote_domid;
kaf24@1127 482 break;
kaf24@1218 483 case ECS_INTERDOMAIN:
kaf24@1218 484 status->status = EVTCHNSTAT_interdomain;
kaf24@2710 485 status->u.interdomain.dom = chn[port].u.interdomain.remote_dom->id;
kaf24@2710 486 status->u.interdomain.port = chn[port].u.interdomain.remote_port;
kaf24@1218 487 break;
kaf24@1218 488 case ECS_PIRQ:
kaf24@1218 489 status->status = EVTCHNSTAT_pirq;
kaf24@1218 490 status->u.pirq = chn[port].u.pirq;
kaf24@1218 491 break;
kaf24@1218 492 case ECS_VIRQ:
kaf24@1218 493 status->status = EVTCHNSTAT_virq;
kaf24@1218 494 status->u.virq = chn[port].u.virq;
kaf24@1127 495 break;
kaf24@1127 496 default:
kaf24@1127 497 BUG();
kaf24@954 498 }
kaf24@954 499
kaf24@1266 500 out:
kaf24@1506 501 spin_unlock(&d->event_channel_lock);
kaf24@1506 502 put_domain(d);
kaf24@1266 503 return rc;
kaf24@954 504 }
kaf24@954 505
kaf24@954 506
kaf24@1127 507 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 508 {
kaf24@954 509 long rc;
kaf24@1127 510 evtchn_op_t op;
kaf24@954 511
kaf24@1127 512 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 513 return -EFAULT;
kaf24@1127 514
kaf24@1127 515 switch ( op.cmd )
kaf24@954 516 {
kaf24@2713 517 case EVTCHNOP_alloc_unbound:
kaf24@2713 518 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 519 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 520 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 521 break;
kaf24@2713 522
kaf24@1218 523 case EVTCHNOP_bind_interdomain:
kaf24@1218 524 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 525 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 526 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 527 break;
kaf24@1218 528
kaf24@1218 529 case EVTCHNOP_bind_virq:
kaf24@1218 530 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 531 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 532 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 533 break;
kaf24@1235 534
kaf24@1235 535 case EVTCHNOP_bind_pirq:
kaf24@1235 536 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 537 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 538 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 539 break;
kaf24@954 540
kaf24@954 541 case EVTCHNOP_close:
kaf24@1218 542 rc = evtchn_close(&op.u.close);
kaf24@954 543 break;
kaf24@954 544
kaf24@954 545 case EVTCHNOP_send:
kaf24@1218 546 rc = evtchn_send(op.u.send.local_port);
kaf24@954 547 break;
kaf24@954 548
kaf24@954 549 case EVTCHNOP_status:
kaf24@1218 550 rc = evtchn_status(&op.u.status);
kaf24@1235 551 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 552 rc = -EFAULT;
kaf24@954 553 break;
kaf24@954 554
kaf24@954 555 default:
kaf24@954 556 rc = -ENOSYS;
kaf24@954 557 break;
kaf24@954 558 }
kaf24@954 559
kaf24@954 560 return rc;
kaf24@954 561 }
kaf24@954 562
kaf24@954 563
kaf24@1506 564 int init_event_channels(struct domain *d)
kaf24@1218 565 {
kaf24@1506 566 spin_lock_init(&d->event_channel_lock);
kaf24@1920 567 d->event_channel = xmalloc(INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 568 if ( unlikely(d->event_channel == NULL) )
kaf24@1218 569 return -ENOMEM;
kaf24@1506 570 d->max_event_channel = INIT_EVENT_CHANNELS;
kaf24@1506 571 memset(d->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 572 d->event_channel[0].state = ECS_VIRQ;
kaf24@1506 573 d->event_channel[0].u.virq = VIRQ_MISDIRECT;
kaf24@1218 574 return 0;
kaf24@1218 575 }
kaf24@1218 576
kaf24@1218 577
kaf24@1506 578 void destroy_event_channels(struct domain *d)
kaf24@954 579 {
kaf24@954 580 int i;
kaf24@1506 581 if ( d->event_channel != NULL )
kaf24@954 582 {
kaf24@1506 583 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 584 (void)__evtchn_close(d, i);
kaf24@1920 585 xfree(d->event_channel);
kaf24@954 586 }
kaf24@954 587 }