ia64/xen-unstable

annotate xen/common/event_channel.c @ 7245:4083eb31def0

Change how event channels are allocated and used by the control
tools. /dev/xen/evtchn is now used by daemons to connect to
remote domains: the advantage is that the local ports are garbage
collected automatically if the daemon dies. xen no longer
constructs end-to-end event-channel port pairs -- it allocates an
unbound port in new domU and writes that port to xenstore. It is
then picked up by teh appropriate daemon which does interdomain bind
via /dev/xen/evtchn.

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