ia64/xen-unstable

annotate xen/common/event_channel.c @ 2929:b12c5094e28c

bitkeeper revision 1.1159.1.400 (4192268botrLPEWBvExDtqcSivVN3g)

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