ia64/xen-unstable

annotate xen/common/event_channel.c @ 2719:bd93b9d866a5

bitkeeper revision 1.1159.130.6 (41793773TFex2kvneKZIR5JlCHOzQQ)

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