ia64/xen-unstable

annotate xen/common/event_channel.c @ 9262:c445d4a0dd76

Define a new sched_op hypercall called sched_op_new, which differs from the
legacy hypercall in that it takes a pointer to a block of extra arguments
rather than an opaque unsigned long. The old hypercall still exists, for
backwards compatibility.

The new hypercall supports new sub-command SCHEDOP_poll, which can be used to
wait on a set of event-channel ports with an optional timeout. This is exported
in XenLinux as HYPERVISOR_poll, and used in the pcifront driver to wait on a
response from the pciback driver.

Can also be used for debuggers. :-)

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