ia64/xen-unstable

annotate xen/common/event_channel.c @ 3297:53a0cc27ab17

bitkeeper revision 1.1159.205.1 (41c1b63cODLXVNkV2OsvJtzvIRxtKg)

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