ia64/xen-unstable

annotate xen/common/event_channel.c @ 3291:37cb59b9ddfd

bitkeeper revision 1.1159.1.484 (41c1a3e20WEWxhNQDQK6avGv36pVEA)

Remove per vcpu misdirect virq support.
author cl349@arcadians.cl.cam.ac.uk
date Thu Dec 16 15:04:02 2004 +0000 (2004-12-16)
parents b9ab4345fd1b
children 53a0cc27ab17 cd90fe329149 3609a4de4be5
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
kaf24@1249 259 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 260 * bound to port 0.
kaf24@1218 261 */
cl349@3291 262 if ( ((port = ed->virq_to_evtchn[virq]) != 0) ||
kaf24@1249 263 (virq == VIRQ_MISDIRECT) ||
cl349@2937 264 ((port = get_free_port(ed)) < 0) )
kaf24@1218 265 goto out;
kaf24@1218 266
kaf24@1506 267 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 268 d->event_channel[port].u.virq = virq;
kaf24@1218 269
cl349@2929 270 ed->virq_to_evtchn[virq] = port;
kaf24@1218 271
kaf24@1218 272 out:
kaf24@1506 273 spin_unlock(&d->event_channel_lock);
kaf24@1218 274
kaf24@1218 275 if ( port < 0 )
kaf24@1218 276 return port;
kaf24@1218 277
kaf24@1218 278 bind->port = port;
cl349@2932 279 return 0;
cl349@2932 280 }
cl349@2932 281
cl349@2932 282 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 283 {
cl349@2932 284 struct exec_domain *ed = current;
cl349@2932 285 struct domain *d = ed->domain;
cl349@2932 286 int port, ipi_edom = bind->ipi_edom;
cl349@2932 287
cl349@2932 288 spin_lock(&d->event_channel_lock);
cl349@2932 289
cl349@2937 290 if ( (port = get_free_port(ed)) >= 0 )
cl349@2932 291 {
cl349@2932 292 d->event_channel[port].state = ECS_IPI;
cl349@2932 293 d->event_channel[port].u.ipi_edom = ipi_edom;
cl349@2932 294 }
cl349@2932 295
cl349@2932 296 spin_unlock(&d->event_channel_lock);
cl349@2932 297
cl349@2932 298 if ( port < 0 )
cl349@2932 299 return port;
cl349@2932 300
cl349@2932 301 bind->port = port;
kaf24@1218 302 return 0;
kaf24@1218 303 }
kaf24@1218 304
kaf24@1218 305
kaf24@1235 306 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 307 {
cl349@2919 308 struct domain *d = current->domain;
kaf24@1506 309 int port, rc, pirq = bind->pirq;
kaf24@1235 310
kaf24@1506 311 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 312 return -EINVAL;
kaf24@1235 313
kaf24@1506 314 spin_lock(&d->event_channel_lock);
kaf24@1235 315
kaf24@1506 316 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
cl349@2937 317 ((rc = port = get_free_port(current)) < 0) )
kaf24@1235 318 goto out;
kaf24@1235 319
kaf24@1506 320 d->pirq_to_evtchn[pirq] = port;
cl349@2924 321 rc = pirq_guest_bind(current, pirq,
kaf24@1253 322 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 323 if ( rc != 0 )
kaf24@1239 324 {
kaf24@1506 325 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 326 goto out;
kaf24@1239 327 }
kaf24@1239 328
kaf24@1506 329 d->event_channel[port].state = ECS_PIRQ;
kaf24@1506 330 d->event_channel[port].u.pirq = pirq;
kaf24@1235 331
kaf24@1235 332 out:
kaf24@1506 333 spin_unlock(&d->event_channel_lock);
kaf24@1235 334
kaf24@1239 335 if ( rc < 0 )
kaf24@1239 336 return rc;
kaf24@1235 337
kaf24@1235 338 bind->port = port;
kaf24@1235 339 return 0;
kaf24@1235 340 }
kaf24@1235 341
kaf24@1235 342
kaf24@1506 343 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 344 {
kaf24@1506 345 struct domain *d2 = NULL;
cl349@2929 346 struct exec_domain *ed;
kaf24@1506 347 event_channel_t *chn1, *chn2;
kaf24@1506 348 int port2;
kaf24@1506 349 long rc = 0;
kaf24@954 350
kaf24@954 351 again:
kaf24@1506 352 spin_lock(&d1->event_channel_lock);
kaf24@954 353
kaf24@1506 354 chn1 = d1->event_channel;
kaf24@954 355
kaf24@1249 356 /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
cl349@3291 357 if ( (port1 <= 0) || (port1 >= d1->max_event_channel) )
kaf24@954 358 {
kaf24@954 359 rc = -EINVAL;
kaf24@954 360 goto out;
kaf24@954 361 }
kaf24@954 362
kaf24@1218 363 switch ( chn1[port1].state )
kaf24@954 364 {
kaf24@1218 365 case ECS_FREE:
kaf24@1218 366 rc = -EINVAL;
kaf24@1218 367 goto out;
kaf24@1218 368
kaf24@1218 369 case ECS_UNBOUND:
kaf24@1218 370 break;
kaf24@1218 371
kaf24@1218 372 case ECS_PIRQ:
kaf24@1506 373 if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
kaf24@1506 374 d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
kaf24@1218 375 break;
kaf24@1218 376
kaf24@1218 377 case ECS_VIRQ:
cl349@2929 378 /* XXX could store exec_domain in chn1[port1].u */
cl349@2929 379 for_each_exec_domain(d1, ed)
cl349@2929 380 if (ed->virq_to_evtchn[chn1[port1].u.virq] == port1)
cl349@2929 381 ed->virq_to_evtchn[chn1[port1].u.virq] = 0;
kaf24@1218 382 break;
kaf24@1218 383
cl349@2932 384 case ECS_IPI:
cl349@2932 385 break;
cl349@2932 386
kaf24@1218 387 case ECS_INTERDOMAIN:
kaf24@1506 388 if ( d2 == NULL )
kaf24@954 389 {
cl349@2924 390 d2 = chn1[port1].u.interdomain.remote_dom->domain;
kaf24@1505 391
kaf24@1506 392 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 393 if ( unlikely(!get_domain(d2)) )
kaf24@1505 394 {
kaf24@1505 395 /*
kaf24@1506 396 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 397 * and so will close this event channel for us.
kaf24@1505 398 */
kaf24@1506 399 d2 = NULL;
kaf24@1505 400 goto out;
kaf24@1505 401 }
kaf24@1127 402
kaf24@1542 403 if ( d1 < d2 )
kaf24@954 404 {
kaf24@1506 405 spin_lock(&d2->event_channel_lock);
kaf24@954 406 }
kaf24@1506 407 else if ( d1 != d2 )
kaf24@954 408 {
kaf24@1506 409 spin_unlock(&d1->event_channel_lock);
kaf24@1506 410 spin_lock(&d2->event_channel_lock);
kaf24@954 411 goto again;
kaf24@954 412 }
kaf24@954 413 }
cl349@2924 414 else if ( d2 != chn1[port1].u.interdomain.remote_dom->domain )
kaf24@954 415 {
kaf24@954 416 rc = -EINVAL;
kaf24@954 417 goto out;
kaf24@954 418 }
kaf24@1505 419
kaf24@1506 420 chn2 = d2->event_channel;
kaf24@2710 421 port2 = chn1[port1].u.interdomain.remote_port;
kaf24@954 422
kaf24@1506 423 if ( port2 >= d2->max_event_channel )
kaf24@1127 424 BUG();
kaf24@1218 425 if ( chn2[port2].state != ECS_INTERDOMAIN )
kaf24@1127 426 BUG();
cl349@2924 427 if ( chn2[port2].u.interdomain.remote_dom->domain != d1 )
kaf24@1127 428 BUG();
kaf24@954 429
kaf24@1258 430 chn2[port2].state = ECS_UNBOUND;
kaf24@2713 431 chn2[port2].u.unbound.remote_domid = d1->id;
kaf24@1218 432 break;
kaf24@1218 433
kaf24@1218 434 default:
kaf24@1218 435 BUG();
kaf24@954 436 }
kaf24@954 437
kaf24@1258 438 chn1[port1].state = ECS_FREE;
kaf24@1133 439
kaf24@954 440 out:
kaf24@1506 441 if ( d2 != NULL )
kaf24@954 442 {
kaf24@1506 443 if ( d1 != d2 )
kaf24@1506 444 spin_unlock(&d2->event_channel_lock);
kaf24@1506 445 put_domain(d2);
kaf24@954 446 }
kaf24@954 447
kaf24@1506 448 spin_unlock(&d1->event_channel_lock);
kaf24@1145 449
kaf24@954 450 return rc;
kaf24@954 451 }
kaf24@954 452
kaf24@954 453
kaf24@1218 454 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 455 {
kaf24@1506 456 struct domain *d;
kaf24@1506 457 long rc;
kaf24@1506 458 domid_t dom = close->dom;
kaf24@1127 459
kaf24@1129 460 if ( dom == DOMID_SELF )
cl349@2919 461 dom = current->domain->id;
cl349@2919 462 else if ( !IS_PRIV(current->domain) )
kaf24@1127 463 return -EPERM;
kaf24@1127 464
kaf24@1506 465 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 466 return -ESRCH;
kaf24@1127 467
kaf24@1506 468 rc = __evtchn_close(d, close->port);
kaf24@1127 469
kaf24@1506 470 put_domain(d);
kaf24@1127 471 return rc;
kaf24@1127 472 }
kaf24@1127 473
kaf24@1127 474
iap10@3290 475 long evtchn_send(int lport)
kaf24@954 476 {
cl349@2924 477 struct domain *ld = current->domain;
cl349@2924 478 struct exec_domain *rd;
cl349@2937 479 int rport, ret = 0;
kaf24@954 480
kaf24@1506 481 spin_lock(&ld->event_channel_lock);
kaf24@954 482
kaf24@1127 483 if ( unlikely(lport < 0) ||
cl349@2937 484 unlikely(lport >= ld->max_event_channel))
kaf24@954 485 {
kaf24@1506 486 spin_unlock(&ld->event_channel_lock);
kaf24@954 487 return -EINVAL;
kaf24@954 488 }
kaf24@954 489
cl349@2937 490 switch ( ld->event_channel[lport].state )
cl349@2937 491 {
cl349@2937 492 case ECS_INTERDOMAIN:
cl349@2937 493 rd = ld->event_channel[lport].u.interdomain.remote_dom;
cl349@2937 494 rport = ld->event_channel[lport].u.interdomain.remote_port;
kaf24@1127 495
cl349@2937 496 evtchn_set_pending(rd, rport);
cl349@2937 497 break;
cl349@2937 498 case ECS_IPI:
cl349@2937 499 rd = ld->exec_domain[ld->event_channel[lport].u.ipi_edom];
cl349@2937 500 if ( rd )
cl349@2937 501 evtchn_set_pending(rd, lport);
cl349@2937 502 else
cl349@2937 503 ret = -EINVAL;
cl349@2937 504 break;
cl349@2937 505 default:
cl349@2937 506 ret = -EINVAL;
cl349@2937 507 }
kaf24@954 508
kaf24@1506 509 spin_unlock(&ld->event_channel_lock);
kaf24@954 510
cl349@2937 511 return ret;
kaf24@954 512 }
kaf24@954 513
kaf24@954 514
kaf24@1218 515 static long evtchn_status(evtchn_status_t *status)
kaf24@954 516 {
kaf24@1506 517 struct domain *d;
kaf24@1506 518 domid_t dom = status->dom;
kaf24@1506 519 int port = status->port;
kaf24@1506 520 event_channel_t *chn;
kaf24@1506 521 long rc = 0;
kaf24@1127 522
kaf24@1129 523 if ( dom == DOMID_SELF )
cl349@2919 524 dom = current->domain->id;
cl349@2919 525 else if ( !IS_PRIV(current->domain) )
kaf24@1127 526 return -EPERM;
kaf24@1127 527
kaf24@1506 528 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 529 return -ESRCH;
kaf24@954 530
kaf24@1506 531 spin_lock(&d->event_channel_lock);
kaf24@954 532
kaf24@1506 533 chn = d->event_channel;
kaf24@954 534
kaf24@1506 535 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 536 {
kaf24@1266 537 rc = -EINVAL;
kaf24@1266 538 goto out;
kaf24@1127 539 }
kaf24@1127 540
kaf24@1129 541 switch ( chn[port].state )
kaf24@1127 542 {
kaf24@1127 543 case ECS_FREE:
kaf24@1127 544 status->status = EVTCHNSTAT_closed;
kaf24@1127 545 break;
kaf24@1218 546 case ECS_UNBOUND:
kaf24@1218 547 status->status = EVTCHNSTAT_unbound;
kaf24@2713 548 status->u.unbound.dom = chn[port].u.unbound.remote_domid;
kaf24@1127 549 break;
kaf24@1218 550 case ECS_INTERDOMAIN:
kaf24@1218 551 status->status = EVTCHNSTAT_interdomain;
cl349@2924 552 status->u.interdomain.dom =
cl349@2924 553 chn[port].u.interdomain.remote_dom->domain->id;
kaf24@2710 554 status->u.interdomain.port = chn[port].u.interdomain.remote_port;
kaf24@1218 555 break;
kaf24@1218 556 case ECS_PIRQ:
kaf24@1218 557 status->status = EVTCHNSTAT_pirq;
kaf24@1218 558 status->u.pirq = chn[port].u.pirq;
kaf24@1218 559 break;
kaf24@1218 560 case ECS_VIRQ:
kaf24@1218 561 status->status = EVTCHNSTAT_virq;
kaf24@1218 562 status->u.virq = chn[port].u.virq;
kaf24@1127 563 break;
cl349@2932 564 case ECS_IPI:
cl349@2932 565 status->status = EVTCHNSTAT_ipi;
cl349@2932 566 status->u.ipi_edom = chn[port].u.ipi_edom;
cl349@2932 567 break;
kaf24@1127 568 default:
kaf24@1127 569 BUG();
kaf24@954 570 }
kaf24@954 571
kaf24@1266 572 out:
kaf24@1506 573 spin_unlock(&d->event_channel_lock);
kaf24@1506 574 put_domain(d);
kaf24@1266 575 return rc;
kaf24@954 576 }
kaf24@954 577
kaf24@954 578
kaf24@1127 579 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 580 {
kaf24@954 581 long rc;
kaf24@1127 582 evtchn_op_t op;
kaf24@954 583
kaf24@1127 584 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 585 return -EFAULT;
kaf24@1127 586
kaf24@1127 587 switch ( op.cmd )
kaf24@954 588 {
kaf24@2713 589 case EVTCHNOP_alloc_unbound:
kaf24@2713 590 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 591 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 592 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 593 break;
kaf24@2713 594
kaf24@1218 595 case EVTCHNOP_bind_interdomain:
kaf24@1218 596 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 597 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 598 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 599 break;
kaf24@1218 600
kaf24@1218 601 case EVTCHNOP_bind_virq:
kaf24@1218 602 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 603 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 604 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 605 break;
kaf24@1235 606
cl349@2932 607 case EVTCHNOP_bind_ipi:
cl349@2932 608 rc = evtchn_bind_ipi(&op.u.bind_ipi);
cl349@2932 609 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
cl349@2932 610 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 611 break;
cl349@2932 612
kaf24@1235 613 case EVTCHNOP_bind_pirq:
kaf24@1235 614 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 615 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 616 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 617 break;
kaf24@954 618
kaf24@954 619 case EVTCHNOP_close:
kaf24@1218 620 rc = evtchn_close(&op.u.close);
kaf24@954 621 break;
kaf24@954 622
kaf24@954 623 case EVTCHNOP_send:
kaf24@1218 624 rc = evtchn_send(op.u.send.local_port);
kaf24@954 625 break;
kaf24@954 626
kaf24@954 627 case EVTCHNOP_status:
kaf24@1218 628 rc = evtchn_status(&op.u.status);
kaf24@1235 629 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 630 rc = -EFAULT;
kaf24@954 631 break;
kaf24@954 632
kaf24@954 633 default:
kaf24@954 634 rc = -ENOSYS;
kaf24@954 635 break;
kaf24@954 636 }
kaf24@954 637
kaf24@954 638 return rc;
kaf24@954 639 }
kaf24@954 640
kaf24@954 641
kaf24@1506 642 int init_event_channels(struct domain *d)
kaf24@1218 643 {
kaf24@1506 644 spin_lock_init(&d->event_channel_lock);
cl349@3291 645 /* Call get_free_port to initialize d->event_channel */
cl349@3291 646 if ( get_free_port(d->exec_domain[0]) != 0 )
cl349@3291 647 return -EINVAL;
cl349@3291 648 d->event_channel[0].state = ECS_VIRQ;
cl349@3291 649 d->event_channel[0].u.virq = VIRQ_MISDIRECT;
cl349@3291 650 return 0;
kaf24@1218 651 }
kaf24@1218 652
kaf24@1218 653
kaf24@1506 654 void destroy_event_channels(struct domain *d)
kaf24@954 655 {
kaf24@954 656 int i;
kaf24@1506 657 if ( d->event_channel != NULL )
kaf24@954 658 {
kaf24@1506 659 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 660 (void)__evtchn_close(d, i);
kaf24@1920 661 xfree(d->event_channel);
kaf24@954 662 }
kaf24@954 663 }