ia64/xen-unstable

annotate xen/common/event_channel.c @ 2924:7ed93ab784b6

bitkeeper revision 1.1159.1.398 (4190c2a3yFTT9r-Ede8ilkq-wZrXkg)

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