ia64/xen-unstable

annotate xen/common/event_channel.c @ 2713:06527e1d6757

bitkeeper revision 1.1159.130.1 (41792c8bfIrnaq8cezNM7nbYpseVFQ)

Extend Xen's evtchn interface.
author kaf24@freefall.cl.cam.ac.uk
date Fri Oct 22 15:51:39 2004 +0000 (2004-10-22)
parents ed0f5b1a41ba
children 77fbe6c094f2 636399a0f740
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@2713 183 break;
kaf24@1329 184
kaf24@2713 185 case ECS_UNBOUND:
kaf24@2713 186 if ( d2->event_channel[port2].u.unbound.remote_domid != dom1 )
kaf24@2713 187 ERROR_EXIT(-EINVAL);
kaf24@2713 188 break;
kaf24@2713 189
kaf24@2713 190 default:
kaf24@2713 191 ERROR_EXIT(-EINVAL);
kaf24@1127 192 }
kaf24@954 193
kaf24@2713 194 /*
kaf24@2713 195 * Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
kaf24@2713 196 */
kaf24@2713 197
kaf24@2710 198 d1->event_channel[port1].u.interdomain.remote_dom = d2;
kaf24@2710 199 d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
kaf24@2713 200 d1->event_channel[port1].state = ECS_INTERDOMAIN;
kaf24@2713 201
kaf24@2710 202 d2->event_channel[port2].u.interdomain.remote_dom = d1;
kaf24@2710 203 d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
kaf24@2710 204 d2->event_channel[port2].state = ECS_INTERDOMAIN;
kaf24@1127 205
kaf24@954 206 out:
kaf24@1506 207 spin_unlock(&d1->event_channel_lock);
kaf24@1506 208 if ( d1 != d2 )
kaf24@1506 209 spin_unlock(&d2->event_channel_lock);
kaf24@1127 210
kaf24@1506 211 put_domain(d1);
kaf24@1506 212 put_domain(d2);
kaf24@1127 213
kaf24@1218 214 bind->port1 = port1;
kaf24@1218 215 bind->port2 = port2;
kaf24@954 216
kaf24@954 217 return rc;
kaf24@2713 218 #undef ERROR_EXIT
kaf24@954 219 }
kaf24@954 220
kaf24@954 221
kaf24@1218 222 static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
kaf24@1218 223 {
kaf24@1506 224 struct domain *d = current;
kaf24@1506 225 int port, virq = bind->virq;
kaf24@1218 226
kaf24@1506 227 if ( virq >= ARRAY_SIZE(d->virq_to_evtchn) )
kaf24@1218 228 return -EINVAL;
kaf24@1218 229
kaf24@1506 230 spin_lock(&d->event_channel_lock);
kaf24@1218 231
kaf24@1218 232 /*
kaf24@1218 233 * Port 0 is the fallback port for VIRQs that haven't been explicitly
kaf24@1249 234 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 235 * bound to port 0.
kaf24@1218 236 */
kaf24@1506 237 if ( ((port = d->virq_to_evtchn[virq]) != 0) ||
kaf24@1249 238 (virq == VIRQ_MISDIRECT) ||
kaf24@1506 239 ((port = get_free_port(d)) < 0) )
kaf24@1218 240 goto out;
kaf24@1218 241
kaf24@1506 242 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 243 d->event_channel[port].u.virq = virq;
kaf24@1218 244
kaf24@1506 245 d->virq_to_evtchn[virq] = port;
kaf24@1218 246
kaf24@1218 247 out:
kaf24@1506 248 spin_unlock(&d->event_channel_lock);
kaf24@1218 249
kaf24@1218 250 if ( port < 0 )
kaf24@1218 251 return port;
kaf24@1218 252
kaf24@1218 253 bind->port = port;
kaf24@1218 254 return 0;
kaf24@1218 255 }
kaf24@1218 256
kaf24@1218 257
kaf24@1235 258 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 259 {
kaf24@1506 260 struct domain *d = current;
kaf24@1506 261 int port, rc, pirq = bind->pirq;
kaf24@1235 262
kaf24@1506 263 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 264 return -EINVAL;
kaf24@1235 265
kaf24@1506 266 spin_lock(&d->event_channel_lock);
kaf24@1235 267
kaf24@1506 268 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
kaf24@1506 269 ((rc = port = get_free_port(d)) < 0) )
kaf24@1235 270 goto out;
kaf24@1235 271
kaf24@1506 272 d->pirq_to_evtchn[pirq] = port;
kaf24@1506 273 rc = pirq_guest_bind(d, pirq,
kaf24@1253 274 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 275 if ( rc != 0 )
kaf24@1239 276 {
kaf24@1506 277 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 278 goto out;
kaf24@1239 279 }
kaf24@1239 280
kaf24@1506 281 d->event_channel[port].state = ECS_PIRQ;
kaf24@1506 282 d->event_channel[port].u.pirq = pirq;
kaf24@1235 283
kaf24@1235 284 out:
kaf24@1506 285 spin_unlock(&d->event_channel_lock);
kaf24@1235 286
kaf24@1239 287 if ( rc < 0 )
kaf24@1239 288 return rc;
kaf24@1235 289
kaf24@1235 290 bind->port = port;
kaf24@1235 291 return 0;
kaf24@1235 292 }
kaf24@1235 293
kaf24@1235 294
kaf24@1506 295 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 296 {
kaf24@1506 297 struct domain *d2 = NULL;
kaf24@1506 298 event_channel_t *chn1, *chn2;
kaf24@1506 299 int port2;
kaf24@1506 300 long rc = 0;
kaf24@954 301
kaf24@954 302 again:
kaf24@1506 303 spin_lock(&d1->event_channel_lock);
kaf24@954 304
kaf24@1506 305 chn1 = d1->event_channel;
kaf24@954 306
kaf24@1249 307 /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
kaf24@1506 308 if ( (port1 <= 0) || (port1 >= d1->max_event_channel) )
kaf24@954 309 {
kaf24@954 310 rc = -EINVAL;
kaf24@954 311 goto out;
kaf24@954 312 }
kaf24@954 313
kaf24@1218 314 switch ( chn1[port1].state )
kaf24@954 315 {
kaf24@1218 316 case ECS_FREE:
kaf24@1218 317 rc = -EINVAL;
kaf24@1218 318 goto out;
kaf24@1218 319
kaf24@1218 320 case ECS_UNBOUND:
kaf24@1218 321 break;
kaf24@1218 322
kaf24@1218 323 case ECS_PIRQ:
kaf24@1506 324 if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
kaf24@1506 325 d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
kaf24@1218 326 break;
kaf24@1218 327
kaf24@1218 328 case ECS_VIRQ:
kaf24@1506 329 d1->virq_to_evtchn[chn1[port1].u.virq] = 0;
kaf24@1218 330 break;
kaf24@1218 331
kaf24@1218 332 case ECS_INTERDOMAIN:
kaf24@1506 333 if ( d2 == NULL )
kaf24@954 334 {
kaf24@2710 335 d2 = chn1[port1].u.interdomain.remote_dom;
kaf24@1505 336
kaf24@1506 337 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 338 if ( unlikely(!get_domain(d2)) )
kaf24@1505 339 {
kaf24@1505 340 /*
kaf24@1506 341 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 342 * and so will close this event channel for us.
kaf24@1505 343 */
kaf24@1506 344 d2 = NULL;
kaf24@1505 345 goto out;
kaf24@1505 346 }
kaf24@1127 347
kaf24@1542 348 if ( d1 < d2 )
kaf24@954 349 {
kaf24@1506 350 spin_lock(&d2->event_channel_lock);
kaf24@954 351 }
kaf24@1506 352 else if ( d1 != d2 )
kaf24@954 353 {
kaf24@1506 354 spin_unlock(&d1->event_channel_lock);
kaf24@1506 355 spin_lock(&d2->event_channel_lock);
kaf24@954 356 goto again;
kaf24@954 357 }
kaf24@954 358 }
kaf24@2710 359 else if ( d2 != chn1[port1].u.interdomain.remote_dom )
kaf24@954 360 {
kaf24@954 361 rc = -EINVAL;
kaf24@954 362 goto out;
kaf24@954 363 }
kaf24@1505 364
kaf24@1506 365 chn2 = d2->event_channel;
kaf24@2710 366 port2 = chn1[port1].u.interdomain.remote_port;
kaf24@954 367
kaf24@1506 368 if ( port2 >= d2->max_event_channel )
kaf24@1127 369 BUG();
kaf24@1218 370 if ( chn2[port2].state != ECS_INTERDOMAIN )
kaf24@1127 371 BUG();
kaf24@2710 372 if ( chn2[port2].u.interdomain.remote_dom != d1 )
kaf24@1127 373 BUG();
kaf24@954 374
kaf24@1258 375 chn2[port2].state = ECS_UNBOUND;
kaf24@2713 376 chn2[port2].u.unbound.remote_domid = d1->id;
kaf24@1218 377 break;
kaf24@1218 378
kaf24@1218 379 default:
kaf24@1218 380 BUG();
kaf24@954 381 }
kaf24@954 382
kaf24@1258 383 chn1[port1].state = ECS_FREE;
kaf24@1133 384
kaf24@954 385 out:
kaf24@1506 386 if ( d2 != NULL )
kaf24@954 387 {
kaf24@1506 388 if ( d1 != d2 )
kaf24@1506 389 spin_unlock(&d2->event_channel_lock);
kaf24@1506 390 put_domain(d2);
kaf24@954 391 }
kaf24@954 392
kaf24@1506 393 spin_unlock(&d1->event_channel_lock);
kaf24@1145 394
kaf24@954 395 return rc;
kaf24@954 396 }
kaf24@954 397
kaf24@954 398
kaf24@1218 399 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 400 {
kaf24@1506 401 struct domain *d;
kaf24@1506 402 long rc;
kaf24@1506 403 domid_t dom = close->dom;
kaf24@1127 404
kaf24@1129 405 if ( dom == DOMID_SELF )
kaf24@2710 406 dom = current->id;
kaf24@1127 407 else if ( !IS_PRIV(current) )
kaf24@1127 408 return -EPERM;
kaf24@1127 409
kaf24@1506 410 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 411 return -ESRCH;
kaf24@1127 412
kaf24@1506 413 rc = __evtchn_close(d, close->port);
kaf24@1127 414
kaf24@1506 415 put_domain(d);
kaf24@1127 416 return rc;
kaf24@1127 417 }
kaf24@1127 418
kaf24@1127 419
kaf24@1218 420 static long evtchn_send(int lport)
kaf24@954 421 {
kaf24@1506 422 struct domain *ld = current, *rd;
kaf24@1506 423 int rport;
kaf24@954 424
kaf24@1506 425 spin_lock(&ld->event_channel_lock);
kaf24@954 426
kaf24@1127 427 if ( unlikely(lport < 0) ||
kaf24@1506 428 unlikely(lport >= ld->max_event_channel) ||
kaf24@1506 429 unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
kaf24@954 430 {
kaf24@1506 431 spin_unlock(&ld->event_channel_lock);
kaf24@954 432 return -EINVAL;
kaf24@954 433 }
kaf24@954 434
kaf24@2710 435 rd = ld->event_channel[lport].u.interdomain.remote_dom;
kaf24@2710 436 rport = ld->event_channel[lport].u.interdomain.remote_port;
kaf24@1127 437
kaf24@1506 438 evtchn_set_pending(rd, rport);
kaf24@954 439
kaf24@1506 440 spin_unlock(&ld->event_channel_lock);
kaf24@954 441
kaf24@954 442 return 0;
kaf24@954 443 }
kaf24@954 444
kaf24@954 445
kaf24@1218 446 static long evtchn_status(evtchn_status_t *status)
kaf24@954 447 {
kaf24@1506 448 struct domain *d;
kaf24@1506 449 domid_t dom = status->dom;
kaf24@1506 450 int port = status->port;
kaf24@1506 451 event_channel_t *chn;
kaf24@1506 452 long rc = 0;
kaf24@1127 453
kaf24@1129 454 if ( dom == DOMID_SELF )
kaf24@2710 455 dom = current->id;
kaf24@1127 456 else if ( !IS_PRIV(current) )
kaf24@1127 457 return -EPERM;
kaf24@1127 458
kaf24@1506 459 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 460 return -ESRCH;
kaf24@954 461
kaf24@1506 462 spin_lock(&d->event_channel_lock);
kaf24@954 463
kaf24@1506 464 chn = d->event_channel;
kaf24@954 465
kaf24@1506 466 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 467 {
kaf24@1266 468 rc = -EINVAL;
kaf24@1266 469 goto out;
kaf24@1127 470 }
kaf24@1127 471
kaf24@1129 472 switch ( chn[port].state )
kaf24@1127 473 {
kaf24@1127 474 case ECS_FREE:
kaf24@1127 475 status->status = EVTCHNSTAT_closed;
kaf24@1127 476 break;
kaf24@1218 477 case ECS_UNBOUND:
kaf24@1218 478 status->status = EVTCHNSTAT_unbound;
kaf24@2713 479 status->u.unbound.dom = chn[port].u.unbound.remote_domid;
kaf24@1127 480 break;
kaf24@1218 481 case ECS_INTERDOMAIN:
kaf24@1218 482 status->status = EVTCHNSTAT_interdomain;
kaf24@2710 483 status->u.interdomain.dom = chn[port].u.interdomain.remote_dom->id;
kaf24@2710 484 status->u.interdomain.port = chn[port].u.interdomain.remote_port;
kaf24@1218 485 break;
kaf24@1218 486 case ECS_PIRQ:
kaf24@1218 487 status->status = EVTCHNSTAT_pirq;
kaf24@1218 488 status->u.pirq = chn[port].u.pirq;
kaf24@1218 489 break;
kaf24@1218 490 case ECS_VIRQ:
kaf24@1218 491 status->status = EVTCHNSTAT_virq;
kaf24@1218 492 status->u.virq = chn[port].u.virq;
kaf24@1127 493 break;
kaf24@1127 494 default:
kaf24@1127 495 BUG();
kaf24@954 496 }
kaf24@954 497
kaf24@1266 498 out:
kaf24@1506 499 spin_unlock(&d->event_channel_lock);
kaf24@1506 500 put_domain(d);
kaf24@1266 501 return rc;
kaf24@954 502 }
kaf24@954 503
kaf24@954 504
kaf24@1127 505 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 506 {
kaf24@954 507 long rc;
kaf24@1127 508 evtchn_op_t op;
kaf24@954 509
kaf24@1127 510 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 511 return -EFAULT;
kaf24@1127 512
kaf24@1127 513 switch ( op.cmd )
kaf24@954 514 {
kaf24@2713 515 case EVTCHNOP_alloc_unbound:
kaf24@2713 516 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 517 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 518 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 519 break;
kaf24@2713 520
kaf24@1218 521 case EVTCHNOP_bind_interdomain:
kaf24@1218 522 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 523 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 524 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 525 break;
kaf24@1218 526
kaf24@1218 527 case EVTCHNOP_bind_virq:
kaf24@1218 528 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 529 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 530 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 531 break;
kaf24@1235 532
kaf24@1235 533 case EVTCHNOP_bind_pirq:
kaf24@1235 534 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 535 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 536 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 537 break;
kaf24@954 538
kaf24@954 539 case EVTCHNOP_close:
kaf24@1218 540 rc = evtchn_close(&op.u.close);
kaf24@954 541 break;
kaf24@954 542
kaf24@954 543 case EVTCHNOP_send:
kaf24@1218 544 rc = evtchn_send(op.u.send.local_port);
kaf24@954 545 break;
kaf24@954 546
kaf24@954 547 case EVTCHNOP_status:
kaf24@1218 548 rc = evtchn_status(&op.u.status);
kaf24@1235 549 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 550 rc = -EFAULT;
kaf24@954 551 break;
kaf24@954 552
kaf24@954 553 default:
kaf24@954 554 rc = -ENOSYS;
kaf24@954 555 break;
kaf24@954 556 }
kaf24@954 557
kaf24@954 558 return rc;
kaf24@954 559 }
kaf24@954 560
kaf24@954 561
kaf24@1506 562 int init_event_channels(struct domain *d)
kaf24@1218 563 {
kaf24@1506 564 spin_lock_init(&d->event_channel_lock);
kaf24@1920 565 d->event_channel = xmalloc(INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 566 if ( unlikely(d->event_channel == NULL) )
kaf24@1218 567 return -ENOMEM;
kaf24@1506 568 d->max_event_channel = INIT_EVENT_CHANNELS;
kaf24@1506 569 memset(d->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 570 d->event_channel[0].state = ECS_VIRQ;
kaf24@1506 571 d->event_channel[0].u.virq = VIRQ_MISDIRECT;
kaf24@1218 572 return 0;
kaf24@1218 573 }
kaf24@1218 574
kaf24@1218 575
kaf24@1506 576 void destroy_event_channels(struct domain *d)
kaf24@954 577 {
kaf24@954 578 int i;
kaf24@1506 579 if ( d->event_channel != NULL )
kaf24@954 580 {
kaf24@1506 581 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 582 (void)__evtchn_close(d, i);
kaf24@1920 583 xfree(d->event_channel);
kaf24@954 584 }
kaf24@954 585 }