ia64/xen-unstable

annotate xen/common/event_channel.c @ 3114:a778ae82fcb3

bitkeeper revision 1.1159.1.451 (41a51866R21ReiS-WH2NSkl2MaBhaA)

Add per exec_domain event_channel initialization.
Make sched_rem_domain/rem_task act on exec_domain.
author cl349@arcadians.cl.cam.ac.uk
date Wed Nov 24 23:25:26 2004 +0000 (2004-11-24)
parents b35c932069a7
children 545088ce72b5
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
cl349@2937 34 static int get_free_port(struct exec_domain *ed)
kaf24@954 35 {
cl349@2937 36 struct domain *d = ed->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
cl349@2937 43 for ( port = ed->eid * 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
kaf24@1920 57 chn = xmalloc(max * sizeof(event_channel_t));
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;
cl349@2924 105 struct exec_domain *ed1, *ed2;
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 )
cl349@2919 117 dom1 = current->domain->id;
kaf24@1129 118 if ( dom2 == DOMID_SELF )
cl349@2919 119 dom2 = current->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
cl349@2924 129 ed1 = d1->exec_domain[0]; /* XXX */
cl349@2924 130 ed2 = d2->exec_domain[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 {
cl349@2937 148 if ( (port1 = get_free_port(ed1)) < 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;
cl349@2937 160 port2 = get_free_port(ed2);
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:
cl349@2924 180 if ( d1->event_channel[port1].u.interdomain.remote_dom != ed2 )
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:
cl349@2924 206 if ( d2->event_channel[port2].u.interdomain.remote_dom != ed1 )
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
cl349@2924 222 d1->event_channel[port1].u.interdomain.remote_dom = ed2;
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
cl349@2924 226 d2->event_channel[port2].u.interdomain.remote_dom = ed1;
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 {
cl349@2929 248 struct exec_domain *ed = current;
cl349@2929 249 struct domain *d = ed->domain;
kaf24@1506 250 int port, virq = bind->virq;
kaf24@1218 251
cl349@2929 252 if ( virq >= ARRAY_SIZE(ed->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
kaf24@1249 259 * bound yet. The exception is the 'misdirect VIRQ', which is permanently
kaf24@1218 260 * bound to port 0.
kaf24@1218 261 */
cl349@3114 262 if ( ((port = ed->virq_to_evtchn[virq]) !=
cl349@3114 263 (ed->eid * EVENT_CHANNELS_SPREAD)) ||
kaf24@1249 264 (virq == VIRQ_MISDIRECT) ||
cl349@2937 265 ((port = get_free_port(ed)) < 0) )
kaf24@1218 266 goto out;
kaf24@1218 267
kaf24@1506 268 d->event_channel[port].state = ECS_VIRQ;
kaf24@1506 269 d->event_channel[port].u.virq = virq;
kaf24@1218 270
cl349@2929 271 ed->virq_to_evtchn[virq] = port;
kaf24@1218 272
kaf24@1218 273 out:
kaf24@1506 274 spin_unlock(&d->event_channel_lock);
kaf24@1218 275
kaf24@1218 276 if ( port < 0 )
kaf24@1218 277 return port;
kaf24@1218 278
kaf24@1218 279 bind->port = port;
cl349@2932 280 printk("evtchn_bind_virq %d/%d virq %d -> %d\n",
cl349@2932 281 d->id, ed->eid, virq, port);
cl349@2932 282 return 0;
cl349@2932 283 }
cl349@2932 284
cl349@2932 285 static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
cl349@2932 286 {
cl349@2932 287 struct exec_domain *ed = current;
cl349@2932 288 struct domain *d = ed->domain;
cl349@2932 289 int port, ipi_edom = bind->ipi_edom;
cl349@2932 290
cl349@2932 291 spin_lock(&d->event_channel_lock);
cl349@2932 292
cl349@2937 293 if ( (port = get_free_port(ed)) >= 0 )
cl349@2932 294 {
cl349@2932 295 d->event_channel[port].state = ECS_IPI;
cl349@2932 296 d->event_channel[port].u.ipi_edom = ipi_edom;
cl349@2932 297 }
cl349@2932 298
cl349@2932 299 spin_unlock(&d->event_channel_lock);
cl349@2932 300
cl349@2932 301 if ( port < 0 )
cl349@2932 302 return port;
cl349@2932 303
cl349@2932 304 bind->port = port;
cl349@2932 305 printk("evtchn_bind_ipi %d/%d ipi_edom %d -> %d\n",
cl349@2932 306 d->id, current->eid, ipi_edom, port);
kaf24@1218 307 return 0;
kaf24@1218 308 }
kaf24@1218 309
kaf24@1218 310
kaf24@1235 311 static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
kaf24@1235 312 {
cl349@2919 313 struct domain *d = current->domain;
kaf24@1506 314 int port, rc, pirq = bind->pirq;
kaf24@1235 315
kaf24@1506 316 if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
kaf24@1235 317 return -EINVAL;
kaf24@1235 318
kaf24@1506 319 spin_lock(&d->event_channel_lock);
kaf24@1235 320
kaf24@1506 321 if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
cl349@2937 322 ((rc = port = get_free_port(current)) < 0) )
kaf24@1235 323 goto out;
kaf24@1235 324
kaf24@1506 325 d->pirq_to_evtchn[pirq] = port;
cl349@2924 326 rc = pirq_guest_bind(current, pirq,
kaf24@1253 327 !!(bind->flags & BIND_PIRQ__WILL_SHARE));
kaf24@1253 328 if ( rc != 0 )
kaf24@1239 329 {
kaf24@1506 330 d->pirq_to_evtchn[pirq] = 0;
kaf24@1239 331 goto out;
kaf24@1239 332 }
kaf24@1239 333
kaf24@1506 334 d->event_channel[port].state = ECS_PIRQ;
kaf24@1506 335 d->event_channel[port].u.pirq = pirq;
kaf24@1235 336
kaf24@1235 337 out:
kaf24@1506 338 spin_unlock(&d->event_channel_lock);
kaf24@1235 339
kaf24@1239 340 if ( rc < 0 )
kaf24@1239 341 return rc;
kaf24@1235 342
kaf24@1235 343 bind->port = port;
cl349@2932 344 printk("evtchn_bind_pirq %d/%d pirq %d -> port %d\n",
cl349@2932 345 d->id, current->eid, pirq, port);
kaf24@1235 346 return 0;
kaf24@1235 347 }
kaf24@1235 348
kaf24@1235 349
kaf24@1506 350 static long __evtchn_close(struct domain *d1, int port1)
kaf24@954 351 {
kaf24@1506 352 struct domain *d2 = NULL;
cl349@2929 353 struct exec_domain *ed;
kaf24@1506 354 event_channel_t *chn1, *chn2;
kaf24@1506 355 int port2;
kaf24@1506 356 long rc = 0;
kaf24@954 357
kaf24@954 358 again:
kaf24@1506 359 spin_lock(&d1->event_channel_lock);
kaf24@954 360
kaf24@1506 361 chn1 = d1->event_channel;
kaf24@954 362
kaf24@1249 363 /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
cl349@3114 364 if ( (port1 <= 0) || (port1 >= d1->max_event_channel) ||
cl349@3114 365 ((port1 & (EVENT_CHANNELS_SPREAD - 1)) == 0) )
kaf24@954 366 {
kaf24@954 367 rc = -EINVAL;
kaf24@954 368 goto out;
kaf24@954 369 }
kaf24@954 370
kaf24@1218 371 switch ( chn1[port1].state )
kaf24@954 372 {
kaf24@1218 373 case ECS_FREE:
kaf24@1218 374 rc = -EINVAL;
kaf24@1218 375 goto out;
kaf24@1218 376
kaf24@1218 377 case ECS_UNBOUND:
kaf24@1218 378 break;
kaf24@1218 379
kaf24@1218 380 case ECS_PIRQ:
kaf24@1506 381 if ( (rc = pirq_guest_unbind(d1, chn1[port1].u.pirq)) == 0 )
kaf24@1506 382 d1->pirq_to_evtchn[chn1[port1].u.pirq] = 0;
kaf24@1218 383 break;
kaf24@1218 384
kaf24@1218 385 case ECS_VIRQ:
cl349@2929 386 /* XXX could store exec_domain in chn1[port1].u */
cl349@2929 387 for_each_exec_domain(d1, ed)
cl349@2929 388 if (ed->virq_to_evtchn[chn1[port1].u.virq] == port1)
cl349@2929 389 ed->virq_to_evtchn[chn1[port1].u.virq] = 0;
kaf24@1218 390 break;
kaf24@1218 391
cl349@2932 392 case ECS_IPI:
cl349@2932 393 break;
cl349@2932 394
kaf24@1218 395 case ECS_INTERDOMAIN:
kaf24@1506 396 if ( d2 == NULL )
kaf24@954 397 {
cl349@2924 398 d2 = chn1[port1].u.interdomain.remote_dom->domain;
kaf24@1505 399
kaf24@1506 400 /* If we unlock d1 then we could lose d2. Must get a reference. */
kaf24@1506 401 if ( unlikely(!get_domain(d2)) )
kaf24@1505 402 {
kaf24@1505 403 /*
kaf24@1506 404 * Failed to obtain a reference. No matter: d2 must be dying
kaf24@1505 405 * and so will close this event channel for us.
kaf24@1505 406 */
kaf24@1506 407 d2 = NULL;
kaf24@1505 408 goto out;
kaf24@1505 409 }
kaf24@1127 410
kaf24@1542 411 if ( d1 < d2 )
kaf24@954 412 {
kaf24@1506 413 spin_lock(&d2->event_channel_lock);
kaf24@954 414 }
kaf24@1506 415 else if ( d1 != d2 )
kaf24@954 416 {
kaf24@1506 417 spin_unlock(&d1->event_channel_lock);
kaf24@1506 418 spin_lock(&d2->event_channel_lock);
kaf24@954 419 goto again;
kaf24@954 420 }
kaf24@954 421 }
cl349@2924 422 else if ( d2 != chn1[port1].u.interdomain.remote_dom->domain )
kaf24@954 423 {
kaf24@954 424 rc = -EINVAL;
kaf24@954 425 goto out;
kaf24@954 426 }
kaf24@1505 427
kaf24@1506 428 chn2 = d2->event_channel;
kaf24@2710 429 port2 = chn1[port1].u.interdomain.remote_port;
kaf24@954 430
kaf24@1506 431 if ( port2 >= d2->max_event_channel )
kaf24@1127 432 BUG();
kaf24@1218 433 if ( chn2[port2].state != ECS_INTERDOMAIN )
kaf24@1127 434 BUG();
cl349@2924 435 if ( chn2[port2].u.interdomain.remote_dom->domain != d1 )
kaf24@1127 436 BUG();
kaf24@954 437
kaf24@1258 438 chn2[port2].state = ECS_UNBOUND;
kaf24@2713 439 chn2[port2].u.unbound.remote_domid = d1->id;
kaf24@1218 440 break;
kaf24@1218 441
kaf24@1218 442 default:
kaf24@1218 443 BUG();
kaf24@954 444 }
kaf24@954 445
kaf24@1258 446 chn1[port1].state = ECS_FREE;
kaf24@1133 447
kaf24@954 448 out:
kaf24@1506 449 if ( d2 != NULL )
kaf24@954 450 {
kaf24@1506 451 if ( d1 != d2 )
kaf24@1506 452 spin_unlock(&d2->event_channel_lock);
kaf24@1506 453 put_domain(d2);
kaf24@954 454 }
kaf24@954 455
kaf24@1506 456 spin_unlock(&d1->event_channel_lock);
kaf24@1145 457
kaf24@954 458 return rc;
kaf24@954 459 }
kaf24@954 460
kaf24@954 461
kaf24@1218 462 static long evtchn_close(evtchn_close_t *close)
kaf24@1127 463 {
kaf24@1506 464 struct domain *d;
kaf24@1506 465 long rc;
kaf24@1506 466 domid_t dom = close->dom;
kaf24@1127 467
kaf24@1129 468 if ( dom == DOMID_SELF )
cl349@2919 469 dom = current->domain->id;
cl349@2919 470 else if ( !IS_PRIV(current->domain) )
kaf24@1127 471 return -EPERM;
kaf24@1127 472
kaf24@1506 473 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 474 return -ESRCH;
kaf24@1127 475
kaf24@1506 476 rc = __evtchn_close(d, close->port);
kaf24@1127 477
kaf24@1506 478 put_domain(d);
kaf24@1127 479 return rc;
kaf24@1127 480 }
kaf24@1127 481
kaf24@1127 482
kaf24@1218 483 static long evtchn_send(int lport)
kaf24@954 484 {
cl349@2924 485 struct domain *ld = current->domain;
cl349@2924 486 struct exec_domain *rd;
cl349@2937 487 int rport, ret = 0;
kaf24@954 488
kaf24@1506 489 spin_lock(&ld->event_channel_lock);
kaf24@954 490
kaf24@1127 491 if ( unlikely(lport < 0) ||
cl349@2937 492 unlikely(lport >= ld->max_event_channel))
kaf24@954 493 {
kaf24@1506 494 spin_unlock(&ld->event_channel_lock);
kaf24@954 495 return -EINVAL;
kaf24@954 496 }
kaf24@954 497
cl349@2937 498 switch ( ld->event_channel[lport].state )
cl349@2937 499 {
cl349@2937 500 case ECS_INTERDOMAIN:
cl349@2937 501 rd = ld->event_channel[lport].u.interdomain.remote_dom;
cl349@2937 502 rport = ld->event_channel[lport].u.interdomain.remote_port;
kaf24@1127 503
cl349@2937 504 evtchn_set_pending(rd, rport);
cl349@2937 505 break;
cl349@2937 506 case ECS_IPI:
cl349@2937 507 rd = ld->exec_domain[ld->event_channel[lport].u.ipi_edom];
cl349@2937 508 if ( rd )
cl349@2937 509 evtchn_set_pending(rd, lport);
cl349@2937 510 else
cl349@2937 511 ret = -EINVAL;
cl349@2937 512 break;
cl349@2937 513 default:
cl349@2937 514 ret = -EINVAL;
cl349@2937 515 }
kaf24@954 516
kaf24@1506 517 spin_unlock(&ld->event_channel_lock);
kaf24@954 518
cl349@2937 519 return ret;
kaf24@954 520 }
kaf24@954 521
kaf24@954 522
kaf24@1218 523 static long evtchn_status(evtchn_status_t *status)
kaf24@954 524 {
kaf24@1506 525 struct domain *d;
kaf24@1506 526 domid_t dom = status->dom;
kaf24@1506 527 int port = status->port;
kaf24@1506 528 event_channel_t *chn;
kaf24@1506 529 long rc = 0;
kaf24@1127 530
kaf24@1129 531 if ( dom == DOMID_SELF )
cl349@2919 532 dom = current->domain->id;
cl349@2919 533 else if ( !IS_PRIV(current->domain) )
kaf24@1127 534 return -EPERM;
kaf24@1127 535
kaf24@1506 536 if ( (d = find_domain_by_id(dom)) == NULL )
kaf24@1127 537 return -ESRCH;
kaf24@954 538
kaf24@1506 539 spin_lock(&d->event_channel_lock);
kaf24@954 540
kaf24@1506 541 chn = d->event_channel;
kaf24@954 542
kaf24@1506 543 if ( (port < 0) || (port >= d->max_event_channel) )
kaf24@954 544 {
kaf24@1266 545 rc = -EINVAL;
kaf24@1266 546 goto out;
kaf24@1127 547 }
kaf24@1127 548
kaf24@1129 549 switch ( chn[port].state )
kaf24@1127 550 {
kaf24@1127 551 case ECS_FREE:
kaf24@1127 552 status->status = EVTCHNSTAT_closed;
kaf24@1127 553 break;
kaf24@1218 554 case ECS_UNBOUND:
kaf24@1218 555 status->status = EVTCHNSTAT_unbound;
kaf24@2713 556 status->u.unbound.dom = chn[port].u.unbound.remote_domid;
kaf24@1127 557 break;
kaf24@1218 558 case ECS_INTERDOMAIN:
kaf24@1218 559 status->status = EVTCHNSTAT_interdomain;
cl349@2924 560 status->u.interdomain.dom =
cl349@2924 561 chn[port].u.interdomain.remote_dom->domain->id;
kaf24@2710 562 status->u.interdomain.port = chn[port].u.interdomain.remote_port;
kaf24@1218 563 break;
kaf24@1218 564 case ECS_PIRQ:
kaf24@1218 565 status->status = EVTCHNSTAT_pirq;
kaf24@1218 566 status->u.pirq = chn[port].u.pirq;
kaf24@1218 567 break;
kaf24@1218 568 case ECS_VIRQ:
kaf24@1218 569 status->status = EVTCHNSTAT_virq;
kaf24@1218 570 status->u.virq = chn[port].u.virq;
kaf24@1127 571 break;
cl349@2932 572 case ECS_IPI:
cl349@2932 573 status->status = EVTCHNSTAT_ipi;
cl349@2932 574 status->u.ipi_edom = chn[port].u.ipi_edom;
cl349@2932 575 break;
kaf24@1127 576 default:
kaf24@1127 577 BUG();
kaf24@954 578 }
kaf24@954 579
kaf24@1266 580 out:
kaf24@1506 581 spin_unlock(&d->event_channel_lock);
kaf24@1506 582 put_domain(d);
kaf24@1266 583 return rc;
kaf24@954 584 }
kaf24@954 585
kaf24@954 586
kaf24@1127 587 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 588 {
kaf24@954 589 long rc;
kaf24@1127 590 evtchn_op_t op;
kaf24@954 591
kaf24@1127 592 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 593 return -EFAULT;
kaf24@1127 594
kaf24@1127 595 switch ( op.cmd )
kaf24@954 596 {
kaf24@2713 597 case EVTCHNOP_alloc_unbound:
kaf24@2713 598 rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
kaf24@2713 599 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@2713 600 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@2713 601 break;
kaf24@2713 602
kaf24@1218 603 case EVTCHNOP_bind_interdomain:
kaf24@1218 604 rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
kaf24@1235 605 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1218 606 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1218 607 break;
kaf24@1218 608
kaf24@1218 609 case EVTCHNOP_bind_virq:
kaf24@1218 610 rc = evtchn_bind_virq(&op.u.bind_virq);
kaf24@1235 611 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1235 612 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@1235 613 break;
kaf24@1235 614
cl349@2932 615 case EVTCHNOP_bind_ipi:
cl349@2932 616 rc = evtchn_bind_ipi(&op.u.bind_ipi);
cl349@2932 617 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
cl349@2932 618 rc = -EFAULT; /* Cleaning up here would be a mess! */
cl349@2932 619 break;
cl349@2932 620
kaf24@1235 621 case EVTCHNOP_bind_pirq:
kaf24@1235 622 rc = evtchn_bind_pirq(&op.u.bind_pirq);
kaf24@1235 623 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 624 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 625 break;
kaf24@954 626
kaf24@954 627 case EVTCHNOP_close:
kaf24@1218 628 rc = evtchn_close(&op.u.close);
kaf24@954 629 break;
kaf24@954 630
kaf24@954 631 case EVTCHNOP_send:
kaf24@1218 632 rc = evtchn_send(op.u.send.local_port);
kaf24@954 633 break;
kaf24@954 634
kaf24@954 635 case EVTCHNOP_status:
kaf24@1218 636 rc = evtchn_status(&op.u.status);
kaf24@1235 637 if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
kaf24@1127 638 rc = -EFAULT;
kaf24@954 639 break;
kaf24@954 640
kaf24@954 641 default:
kaf24@954 642 rc = -ENOSYS;
kaf24@954 643 break;
kaf24@954 644 }
kaf24@954 645
kaf24@954 646 return rc;
kaf24@954 647 }
kaf24@954 648
kaf24@954 649
cl349@3114 650 int init_exec_domain_event_channels(struct exec_domain *ed)
cl349@3114 651 {
cl349@3114 652 struct domain *d = ed->domain;
cl349@3114 653 int port, ret = -EINVAL, virq;
cl349@3114 654
cl349@3114 655 spin_lock(&d->event_channel_lock);
cl349@3114 656 port = ed->eid * EVENT_CHANNELS_SPREAD;
cl349@3114 657 if ( ((port < d->max_event_channel &&
cl349@3114 658 d->event_channel[port].state != ECS_FREE)) ||
cl349@3114 659 (get_free_port(ed) != port) )
cl349@3114 660 goto out;
cl349@3114 661 d->event_channel[port].state = ECS_VIRQ;
cl349@3114 662 d->event_channel[port].u.virq = VIRQ_MISDIRECT;
cl349@3114 663 for ( virq = 0; virq < NR_VIRQS; virq++ )
cl349@3114 664 ed->virq_to_evtchn[virq] = port;
cl349@3114 665 ret = 0;
cl349@3114 666 out:
cl349@3114 667 spin_unlock(&d->event_channel_lock);
cl349@3114 668 return ret;
cl349@3114 669 }
cl349@3114 670
kaf24@1506 671 int init_event_channels(struct domain *d)
kaf24@1218 672 {
kaf24@1506 673 spin_lock_init(&d->event_channel_lock);
cl349@3114 674 return init_exec_domain_event_channels(d->exec_domain[0]);
kaf24@1218 675 }
kaf24@1218 676
kaf24@1218 677
kaf24@1506 678 void destroy_event_channels(struct domain *d)
kaf24@954 679 {
kaf24@954 680 int i;
kaf24@1506 681 if ( d->event_channel != NULL )
kaf24@954 682 {
kaf24@1506 683 for ( i = 0; i < d->max_event_channel; i++ )
kaf24@1506 684 (void)__evtchn_close(d, i);
kaf24@1920 685 xfree(d->event_channel);
kaf24@954 686 }
kaf24@954 687 }