ia64/xen-unstable

annotate xen/common/event_channel.c @ 5325:66803c3fa4fd

bitkeeper revision 1.1674 (42a2cfb9WFgnh2K4Xr5ev3pSEASVbw)

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