ia64/xen-unstable

annotate xen/common/event_channel.c @ 5289:cd10a0139388

bitkeeper revision 1.1644.1.1 (429f749dKFzVUg9NXDMVu4apHJvpNQ)

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