ia64/xen-unstable

annotate xen/common/event_channel.c @ 2932:cbdc0480194e

bitkeeper revision 1.1159.1.401 (41923739R6r2c-dNxHPSxOagRn-R3g)

Setup cpu-local interrupt handline.
Add support for ipi event channels.
author cl349@freefall.cl.cam.ac.uk
date Wed Nov 10 15:43:53 2004 +0000 (2004-11-10)
parents b12c5094e28c
children b35c932069a7
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@2929 242 struct exec_domain *ed = current;
cl349@2929 243 struct domain *d = ed->domain;
kaf24@1506 244 int port, virq = bind->virq;
kaf24@1218 245
cl349@2929 246 if ( virq >= ARRAY_SIZE(ed->virq_to_evtchn) )
kaf24@1218 247 return -EINVAL;
kaf24@1218 248
kaf24@1506 249 spin_lock(&d->event_channel_lock);
kaf24@1218 250
kaf24@1218 251 /*
kaf24@1218 252 * Port 0 is the fallback port for VIRQs that haven't been explicitly
kaf24@1249 253 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 254 * bound to port 0.
kaf24@1218 255 */
cl349@2929 256 if ( ((port = ed->virq_to_evtchn[virq]) != 0) ||
kaf24@1249 257 (virq == VIRQ_MISDIRECT) ||
kaf24@1506 258 ((port = get_free_port(d)) < 0) )
kaf24@1218 259 goto out;
kaf24@1218 260
kaf24@1506 261 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 262 d->event_channel[port].u.virq = virq;
kaf24@1218 263
cl349@2929 264 ed->virq_to_evtchn[virq] = port;
kaf24@1218 265
kaf24@1218 266 out:
kaf24@1506 267 spin_unlock(&d->event_channel_lock);
kaf24@1218 268
kaf24@1218 269 if ( port < 0 )
kaf24@1218 270 return port;
kaf24@1218 271
kaf24@1218 272 bind->port = port;
cl349@2932 273 printk("evtchn_bind_virq %d/%d virq %d -> %d\n",
cl349@2932 274 d->id, ed->eid, virq, port);
cl349@2932 275 return 0;
cl349@2932 276 }
cl349@2932 277
cl349@2932 278 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 279 {
cl349@2932 280 struct exec_domain *ed = current;
cl349@2932 281 struct domain *d = ed->domain;
cl349@2932 282 int port, ipi_edom = bind->ipi_edom;
cl349@2932 283
cl349@2932 284 spin_lock(&d->event_channel_lock);
cl349@2932 285
cl349@2932 286 if ( (port = get_free_port(d)) >= 0 )
cl349@2932 287 {
cl349@2932 288 d->event_channel[port].state = ECS_IPI;
cl349@2932 289 d->event_channel[port].u.ipi_edom = ipi_edom;
cl349@2932 290 }
cl349@2932 291
cl349@2932 292 spin_unlock(&d->event_channel_lock);
cl349@2932 293
cl349@2932 294 if ( port < 0 )
cl349@2932 295 return port;
cl349@2932 296
cl349@2932 297 bind->port = port;
cl349@2932 298 printk("evtchn_bind_ipi %d/%d ipi_edom %d -> %d\n",
cl349@2932 299 d->id, current->eid, ipi_edom, 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) ||
kaf24@1506 315 ((rc = port = get_free_port(d)) < 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;
cl349@2932 337 printk("evtchn_bind_pirq %d/%d pirq %d -> port %d\n",
cl349@2932 338 d->id, current->eid, pirq, 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. */
kaf24@1506 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
kaf24@1218 475 static long evtchn_send(int lport)
kaf24@954 476 {
cl349@2924 477 struct domain *ld = current->domain;
cl349@2924 478 struct exec_domain *rd;
kaf24@1506 479 int rport;
kaf24@954 480
kaf24@1506 481 spin_lock(&ld->event_channel_lock);
kaf24@954 482
kaf24@1127 483 if ( unlikely(lport < 0) ||
kaf24@1506 484 unlikely(lport >= ld->max_event_channel) ||
kaf24@1506 485 unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
kaf24@954 486 {
kaf24@1506 487 spin_unlock(&ld->event_channel_lock);
kaf24@954 488 return -EINVAL;
kaf24@954 489 }
kaf24@954 490
kaf24@2710 491 rd = ld->event_channel[lport].u.interdomain.remote_dom;
kaf24@2710 492 rport = ld->event_channel[lport].u.interdomain.remote_port;
kaf24@1127 493
kaf24@1506 494 evtchn_set_pending(rd, rport);
kaf24@954 495
kaf24@1506 496 spin_unlock(&ld->event_channel_lock);
kaf24@954 497
kaf24@954 498 return 0;
kaf24@954 499 }
kaf24@954 500
kaf24@954 501
kaf24@1218 502 static long evtchn_status(evtchn_status_t *status)
kaf24@954 503 {
kaf24@1506 504 struct domain *d;
kaf24@1506 505 domid_t dom = status->dom;
kaf24@1506 506 int port = status->port;
kaf24@1506 507 event_channel_t *chn;
kaf24@1506 508 long rc = 0;
kaf24@1127 509
kaf24@1129 510 if ( dom == DOMID_SELF )
cl349@2919 511 dom = current->domain->id;
cl349@2919 512 else if ( !IS_PRIV(current->domain) )
kaf24@1127 513 return -EPERM;
kaf24@1127 514
kaf24@1506 515 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 516 return -ESRCH;
kaf24@954 517
kaf24@1506 518 spin_lock(&d->event_channel_lock);
kaf24@954 519
kaf24@1506 520 chn = d->event_channel;
kaf24@954 521
kaf24@1506 522 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 523 {
kaf24@1266 524 rc = -EINVAL;
kaf24@1266 525 goto out;
kaf24@1127 526 }
kaf24@1127 527
kaf24@1129 528 switch ( chn[port].state )
kaf24@1127 529 {
kaf24@1127 530 case ECS_FREE:
kaf24@1127 531 status->status = EVTCHNSTAT_closed;
kaf24@1127 532 break;
kaf24@1218 533 case ECS_UNBOUND:
kaf24@1218 534 status->status = EVTCHNSTAT_unbound;
kaf24@2713 535 status->u.unbound.dom = chn[port].u.unbound.remote_domid;
kaf24@1127 536 break;
kaf24@1218 537 case ECS_INTERDOMAIN:
kaf24@1218 538 status->status = EVTCHNSTAT_interdomain;
cl349@2924 539 status->u.interdomain.dom =
cl349@2924 540 chn[port].u.interdomain.remote_dom->domain->id;
kaf24@2710 541 status->u.interdomain.port = chn[port].u.interdomain.remote_port;
kaf24@1218 542 break;
kaf24@1218 543 case ECS_PIRQ:
kaf24@1218 544 status->status = EVTCHNSTAT_pirq;
kaf24@1218 545 status->u.pirq = chn[port].u.pirq;
kaf24@1218 546 break;
kaf24@1218 547 case ECS_VIRQ:
kaf24@1218 548 status->status = EVTCHNSTAT_virq;
kaf24@1218 549 status->u.virq = chn[port].u.virq;
kaf24@1127 550 break;
cl349@2932 551 case ECS_IPI:
cl349@2932 552 status->status = EVTCHNSTAT_ipi;
cl349@2932 553 status->u.ipi_edom = chn[port].u.ipi_edom;
cl349@2932 554 break;
kaf24@1127 555 default:
kaf24@1127 556 BUG();
kaf24@954 557 }
kaf24@954 558
kaf24@1266 559 out:
kaf24@1506 560 spin_unlock(&d->event_channel_lock);
kaf24@1506 561 put_domain(d);
kaf24@1266 562 return rc;
kaf24@954 563 }
kaf24@954 564
kaf24@954 565
kaf24@1127 566 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 567 {
kaf24@954 568 long rc;
kaf24@1127 569 evtchn_op_t op;
kaf24@954 570
kaf24@1127 571 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 572 return -EFAULT;
kaf24@1127 573
kaf24@1127 574 switch ( op.cmd )
kaf24@954 575 {
kaf24@2713 576 case EVTCHNOP_alloc_unbound:
kaf24@2713 577 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 578 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 579 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 580 break;
kaf24@2713 581
kaf24@1218 582 case EVTCHNOP_bind_interdomain:
kaf24@1218 583 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 584 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 585 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 586 break;
kaf24@1218 587
kaf24@1218 588 case EVTCHNOP_bind_virq:
kaf24@1218 589 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 590 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 591 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 592 break;
kaf24@1235 593
cl349@2932 594 case EVTCHNOP_bind_ipi:
cl349@2932 595 rc = evtchn_bind_ipi(&op.u.bind_ipi);
cl349@2932 596 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
cl349@2932 597 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 598 break;
cl349@2932 599
kaf24@1235 600 case EVTCHNOP_bind_pirq:
kaf24@1235 601 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 602 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 603 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 604 break;
kaf24@954 605
kaf24@954 606 case EVTCHNOP_close:
kaf24@1218 607 rc = evtchn_close(&op.u.close);
kaf24@954 608 break;
kaf24@954 609
kaf24@954 610 case EVTCHNOP_send:
kaf24@1218 611 rc = evtchn_send(op.u.send.local_port);
kaf24@954 612 break;
kaf24@954 613
kaf24@954 614 case EVTCHNOP_status:
kaf24@1218 615 rc = evtchn_status(&op.u.status);
kaf24@1235 616 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 617 rc = -EFAULT;
kaf24@954 618 break;
kaf24@954 619
kaf24@954 620 default:
kaf24@954 621 rc = -ENOSYS;
kaf24@954 622 break;
kaf24@954 623 }
kaf24@954 624
kaf24@954 625 return rc;
kaf24@954 626 }
kaf24@954 627
kaf24@954 628
kaf24@1506 629 int init_event_channels(struct domain *d)
kaf24@1218 630 {
kaf24@1506 631 spin_lock_init(&d->event_channel_lock);
kaf24@1920 632 d->event_channel = xmalloc(INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 633 if ( unlikely(d->event_channel == NULL) )
kaf24@1218 634 return -ENOMEM;
kaf24@1506 635 d->max_event_channel = INIT_EVENT_CHANNELS;
kaf24@1506 636 memset(d->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
kaf24@1506 637 d->event_channel[0].state = ECS_VIRQ;
kaf24@1506 638 d->event_channel[0].u.virq = VIRQ_MISDIRECT;
kaf24@1218 639 return 0;
kaf24@1218 640 }
kaf24@1218 641
kaf24@1218 642
kaf24@1506 643 void destroy_event_channels(struct domain *d)
kaf24@954 644 {
kaf24@954 645 int i;
kaf24@1506 646 if ( d->event_channel != NULL )
kaf24@954 647 {
kaf24@1506 648 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 649 (void)__evtchn_close(d, i);
kaf24@1920 650 xfree(d->event_channel);
kaf24@954 651 }
kaf24@954 652 }