ia64/xen-unstable

annotate xen/common/event_channel.c @ 1129:6baeead2cccd

bitkeeper revision 1.749.1.2 (403e097cnc0BYoVqLwFH7-TpqyBF_w)

xc_evtchn.c:
new file
event_channel.h, event_channel.c, Xc.c, xc_private.h, xc.h:
Plumb event channels thru to Python wrapper.
author kaf24@scramble.cl.cam.ac.uk
date Thu Feb 26 14:58:04 2004 +0000 (2004-02-26)
parents 9ed81ff882d4
children acd0f2cab313
rev   line source
kaf24@954 1 /******************************************************************************
kaf24@954 2 * event_channel.c
kaf24@954 3 *
kaf24@954 4 * Event channels between 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@954 18 #include <xeno/config.h>
kaf24@954 19 #include <xeno/init.h>
kaf24@954 20 #include <xeno/lib.h>
kaf24@954 21 #include <xeno/errno.h>
kaf24@954 22 #include <xeno/sched.h>
kaf24@954 23 #include <xeno/event.h>
kaf24@954 24
kaf24@1127 25 #include <hypervisor-ifs/hypervisor-if.h>
kaf24@1127 26 #include <hypervisor-ifs/event_channel.h>
kaf24@1127 27
kaf24@956 28 #define MAX_EVENT_CHANNELS 1024
kaf24@954 29
kaf24@1127 30 static int get_free_port(struct task_struct *p)
kaf24@954 31 {
kaf24@1127 32 int max, port;
kaf24@1127 33 event_channel_t *chn;
kaf24@1127 34
kaf24@1127 35 max = p->max_event_channel;
kaf24@1127 36 chn = p->event_channel;
kaf24@1127 37
kaf24@1127 38 for ( port = 0; port < max; port++ )
kaf24@1127 39 if ( chn[port].state == ECS_FREE )
kaf24@1127 40 break;
kaf24@1127 41
kaf24@1127 42 if ( port == max )
kaf24@1127 43 {
kaf24@1127 44 if ( max == MAX_EVENT_CHANNELS )
kaf24@1127 45 return -ENOSPC;
kaf24@1127 46
kaf24@1127 47 max = (max == 0) ? 4 : (max * 2);
kaf24@1127 48
kaf24@1127 49 chn = kmalloc(max * sizeof(event_channel_t), GFP_KERNEL);
kaf24@1127 50 if ( unlikely(chn == NULL) )
kaf24@1127 51 return -ENOMEM;
kaf24@1127 52
kaf24@1127 53 memset(chn, 0, max * sizeof(event_channel_t));
kaf24@1127 54
kaf24@1127 55 if ( p->event_channel != NULL )
kaf24@1127 56 {
kaf24@1127 57 memcpy(chn, p->event_channel, (max/2) * sizeof(event_channel_t));
kaf24@1127 58 kfree(p->event_channel);
kaf24@1127 59 }
kaf24@1127 60
kaf24@1127 61 p->event_channel = chn;
kaf24@1127 62 p->max_event_channel = max;
kaf24@1127 63 }
kaf24@1127 64
kaf24@1127 65 return port;
kaf24@1127 66 }
kaf24@1127 67
kaf24@1127 68 static inline unsigned long set_event_pending(struct task_struct *p, int port)
kaf24@1127 69 {
kaf24@1127 70 if ( !test_and_set_bit(port, &p->shared_info->event_channel_pend[0]) &&
kaf24@1127 71 !test_and_set_bit(port>>5, &p->shared_info->event_channel_pend_sel) )
kaf24@1127 72 return mark_guest_event(p, _EVENT_EVTCHN);
kaf24@1127 73 return 0;
kaf24@1127 74 }
kaf24@1127 75
kaf24@1127 76 static inline unsigned long set_event_disc(struct task_struct *p, int port)
kaf24@1127 77 {
kaf24@1127 78 if ( !test_and_set_bit(port, &p->shared_info->event_channel_disc[0]) &&
kaf24@1127 79 !test_and_set_bit(port>>5, &p->shared_info->event_channel_disc_sel) )
kaf24@1127 80 return mark_guest_event(p, _EVENT_EVTCHN);
kaf24@1127 81 return 0;
kaf24@1127 82 }
kaf24@1127 83
kaf24@1127 84 static long event_channel_open(evtchn_open_t *open)
kaf24@1127 85 {
kaf24@1129 86 struct task_struct *p1, *p2;
kaf24@1129 87 int port1 = 0, port2 = 0;
kaf24@954 88 unsigned long cpu_mask;
kaf24@1129 89 domid_t dom1 = open->dom1, dom2 = open->dom2;
kaf24@954 90 long rc = 0;
kaf24@954 91
kaf24@1127 92 if ( !IS_PRIV(current) )
kaf24@1127 93 return -EPERM;
kaf24@954 94
kaf24@1129 95 /* 'dom1' may be DOMID_SELF. 'dom2' cannot be.*/
kaf24@1129 96 if ( dom1 == DOMID_SELF )
kaf24@1129 97 dom1 = current->domain;
kaf24@1129 98 if ( dom2 == DOMID_SELF )
kaf24@1129 99 return -EINVAL;
kaf24@1127 100
kaf24@1127 101 /* Event channel must connect distinct domains. */
kaf24@1129 102 if ( dom1 == dom2 )
kaf24@1127 103 return -EINVAL;
kaf24@1127 104
kaf24@1129 105 if ( ((p1 = find_domain_by_id(dom1)) == NULL) ||
kaf24@1129 106 ((p2 = find_domain_by_id(dom2)) == NULL) )
kaf24@1127 107 {
kaf24@1129 108 if ( p1 != NULL )
kaf24@1129 109 put_task_struct(p1);
kaf24@1127 110 return -ESRCH;
kaf24@1127 111 }
kaf24@1127 112
kaf24@1127 113 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@1129 114 if ( dom1 < dom2 )
kaf24@954 115 {
kaf24@1129 116 spin_lock(&p1->event_channel_lock);
kaf24@1129 117 spin_lock(&p2->event_channel_lock);
kaf24@954 118 }
kaf24@954 119 else
kaf24@954 120 {
kaf24@1129 121 spin_lock(&p2->event_channel_lock);
kaf24@1129 122 spin_lock(&p1->event_channel_lock);
kaf24@954 123 }
kaf24@954 124
kaf24@1129 125 if ( (port1 = get_free_port(p1)) < 0 )
kaf24@954 126 {
kaf24@1129 127 rc = port1;
kaf24@1127 128 goto out;
kaf24@954 129 }
kaf24@954 130
kaf24@1129 131 if ( (port2 = get_free_port(p2)) < 0 )
kaf24@954 132 {
kaf24@1129 133 rc = port2;
kaf24@1127 134 goto out;
kaf24@1127 135 }
kaf24@954 136
kaf24@1129 137 p1->event_channel[port1].remote_dom = p2;
kaf24@1129 138 p1->event_channel[port1].remote_port = (u16)port2;
kaf24@1129 139 p1->event_channel[port1].state = ECS_CONNECTED;
kaf24@954 140
kaf24@1129 141 p2->event_channel[port2].remote_dom = p1;
kaf24@1129 142 p2->event_channel[port2].remote_port = (u16)port1;
kaf24@1129 143 p2->event_channel[port2].state = ECS_CONNECTED;
kaf24@1127 144
kaf24@1129 145 cpu_mask = set_event_pending(p1, port1);
kaf24@1129 146 cpu_mask |= set_event_pending(p2, port2);
kaf24@1127 147 guest_event_notify(cpu_mask);
kaf24@954 148
kaf24@954 149 out:
kaf24@1129 150 spin_unlock(&p1->event_channel_lock);
kaf24@1129 151 spin_unlock(&p2->event_channel_lock);
kaf24@1127 152
kaf24@1129 153 put_task_struct(p1);
kaf24@1129 154 put_task_struct(p2);
kaf24@1127 155
kaf24@1129 156 open->port1 = port1;
kaf24@1129 157 open->port2 = port2;
kaf24@954 158
kaf24@954 159 return rc;
kaf24@954 160 }
kaf24@954 161
kaf24@954 162
kaf24@1129 163 static long __event_channel_close(struct task_struct *p1, int port1)
kaf24@954 164 {
kaf24@1129 165 struct task_struct *p2 = NULL;
kaf24@1129 166 event_channel_t *chn1, *chn2;
kaf24@1129 167 int port2;
kaf24@954 168 unsigned long cpu_mask;
kaf24@954 169 long rc = 0;
kaf24@954 170
kaf24@954 171 again:
kaf24@1129 172 spin_lock(&p1->event_channel_lock);
kaf24@954 173
kaf24@1129 174 chn1 = p1->event_channel;
kaf24@954 175
kaf24@1129 176 if ( (port1 < 0) || (port1 >= p1->max_event_channel) ||
kaf24@1129 177 (chn1[port1].state == ECS_FREE) )
kaf24@954 178 {
kaf24@954 179 rc = -EINVAL;
kaf24@954 180 goto out;
kaf24@954 181 }
kaf24@954 182
kaf24@1129 183 if ( chn1[port1].state == ECS_CONNECTED )
kaf24@954 184 {
kaf24@1129 185 if ( p2 == NULL )
kaf24@954 186 {
kaf24@1129 187 p2 = chn1[port1].remote_dom;
kaf24@1129 188 get_task_struct(p2);
kaf24@1127 189
kaf24@1129 190 if ( p1->domain < p2->domain )
kaf24@954 191 {
kaf24@1129 192 spin_lock(&p2->event_channel_lock);
kaf24@954 193 }
kaf24@954 194 else
kaf24@954 195 {
kaf24@1129 196 spin_unlock(&p1->event_channel_lock);
kaf24@1129 197 spin_lock(&p2->event_channel_lock);
kaf24@954 198 goto again;
kaf24@954 199 }
kaf24@954 200 }
kaf24@1129 201 else if ( p2 != chn1[port1].remote_dom )
kaf24@954 202 {
kaf24@954 203 rc = -EINVAL;
kaf24@954 204 goto out;
kaf24@954 205 }
kaf24@954 206
kaf24@1129 207 chn2 = p2->event_channel;
kaf24@1129 208 port2 = chn1[port1].remote_port;
kaf24@954 209
kaf24@1129 210 if ( port2 >= p2->max_event_channel )
kaf24@1127 211 BUG();
kaf24@1129 212 if ( chn2[port2].state != ECS_CONNECTED )
kaf24@1127 213 BUG();
kaf24@1129 214 if ( chn2[port2].remote_dom != p1 )
kaf24@1127 215 BUG();
kaf24@954 216
kaf24@1129 217 chn2[port2].state = ECS_ZOMBIE;
kaf24@1129 218 chn2[port2].remote_dom = NULL;
kaf24@1129 219 chn2[port2].remote_port = 0xFFFF;
kaf24@1127 220
kaf24@1129 221 cpu_mask = set_event_disc(p1, port1);
kaf24@1129 222 cpu_mask |= set_event_disc(p2, port2);
kaf24@1127 223 guest_event_notify(cpu_mask);
kaf24@954 224 }
kaf24@954 225
kaf24@1129 226 chn1[port1].state = ECS_FREE;
kaf24@1129 227 chn1[port1].remote_dom = NULL;
kaf24@1129 228 chn1[port1].remote_port = 0xFFFF;
kaf24@954 229
kaf24@954 230 out:
kaf24@1129 231 spin_unlock(&p1->event_channel_lock);
kaf24@1129 232 put_task_struct(p1);
kaf24@1127 233
kaf24@1129 234 if ( p2 != NULL )
kaf24@954 235 {
kaf24@1129 236 spin_unlock(&p2->event_channel_lock);
kaf24@1129 237 put_task_struct(p2);
kaf24@954 238 }
kaf24@954 239
kaf24@954 240 return rc;
kaf24@954 241 }
kaf24@954 242
kaf24@954 243
kaf24@1127 244 static long event_channel_close(evtchn_close_t *close)
kaf24@1127 245 {
kaf24@1129 246 struct task_struct *p;
kaf24@1127 247 long rc;
kaf24@1129 248 domid_t dom = close->dom;
kaf24@1127 249
kaf24@1129 250 if ( dom == DOMID_SELF )
kaf24@1129 251 dom = current->domain;
kaf24@1127 252 else if ( !IS_PRIV(current) )
kaf24@1127 253 return -EPERM;
kaf24@1127 254
kaf24@1129 255 if ( (p = find_domain_by_id(dom)) == NULL )
kaf24@1127 256 return -ESRCH;
kaf24@1127 257
kaf24@1129 258 rc = __event_channel_close(p, close->port);
kaf24@1127 259
kaf24@1129 260 put_task_struct(p);
kaf24@1127 261 return rc;
kaf24@1127 262 }
kaf24@1127 263
kaf24@1127 264
kaf24@1127 265 static long event_channel_send(int lport)
kaf24@954 266 {
kaf24@954 267 struct task_struct *lp = current, *rp;
kaf24@1127 268 int rport;
kaf24@954 269 unsigned long cpu_mask;
kaf24@954 270
kaf24@954 271 spin_lock(&lp->event_channel_lock);
kaf24@954 272
kaf24@1127 273 if ( unlikely(lport < 0) ||
kaf24@1127 274 unlikely(lport >= lp->max_event_channel) ||
kaf24@1127 275 unlikely(lp->event_channel[lport].state != ECS_CONNECTED) )
kaf24@954 276 {
kaf24@954 277 spin_unlock(&lp->event_channel_lock);
kaf24@954 278 return -EINVAL;
kaf24@954 279 }
kaf24@954 280
kaf24@1127 281 rp = lp->event_channel[lport].remote_dom;
kaf24@1127 282 rport = lp->event_channel[lport].remote_port;
kaf24@1127 283
kaf24@1127 284 get_task_struct(rp);
kaf24@954 285
kaf24@954 286 spin_unlock(&lp->event_channel_lock);
kaf24@954 287
kaf24@1127 288 cpu_mask = set_event_pending(rp, rport);
kaf24@1127 289 guest_event_notify(cpu_mask);
kaf24@954 290
kaf24@954 291 put_task_struct(rp);
kaf24@1127 292
kaf24@954 293 return 0;
kaf24@954 294 }
kaf24@954 295
kaf24@954 296
kaf24@1127 297 static long event_channel_status(evtchn_status_t *status)
kaf24@954 298 {
kaf24@1129 299 struct task_struct *p;
kaf24@1129 300 domid_t dom = status->dom1;
kaf24@1129 301 int port = status->port1;
kaf24@1129 302 event_channel_t *chn;
kaf24@1127 303
kaf24@1129 304 if ( dom == DOMID_SELF )
kaf24@1129 305 dom = current->domain;
kaf24@1127 306 else if ( !IS_PRIV(current) )
kaf24@1127 307 return -EPERM;
kaf24@1127 308
kaf24@1129 309 if ( (p = find_domain_by_id(dom)) == NULL )
kaf24@1127 310 return -ESRCH;
kaf24@954 311
kaf24@1129 312 spin_lock(&p->event_channel_lock);
kaf24@954 313
kaf24@1129 314 chn = p->event_channel;
kaf24@954 315
kaf24@1129 316 if ( (port < 0) || (port >= p->max_event_channel) )
kaf24@954 317 {
kaf24@1129 318 spin_unlock(&p->event_channel_lock);
kaf24@1127 319 return -EINVAL;
kaf24@1127 320 }
kaf24@1127 321
kaf24@1129 322 switch ( chn[port].state )
kaf24@1127 323 {
kaf24@1127 324 case ECS_FREE:
kaf24@1127 325 status->status = EVTCHNSTAT_closed;
kaf24@1127 326 break;
kaf24@1127 327 case ECS_ZOMBIE:
kaf24@1127 328 status->status = EVTCHNSTAT_disconnected;
kaf24@1127 329 break;
kaf24@1127 330 case ECS_CONNECTED:
kaf24@1127 331 status->status = EVTCHNSTAT_connected;
kaf24@1129 332 status->dom2 = chn[port].remote_dom->domain;
kaf24@1129 333 status->port2 = chn[port].remote_port;
kaf24@1127 334 break;
kaf24@1127 335 default:
kaf24@1127 336 BUG();
kaf24@954 337 }
kaf24@954 338
kaf24@1129 339 spin_unlock(&p->event_channel_lock);
kaf24@1127 340 return 0;
kaf24@954 341 }
kaf24@954 342
kaf24@954 343
kaf24@1127 344 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 345 {
kaf24@954 346 long rc;
kaf24@1127 347 evtchn_op_t op;
kaf24@954 348
kaf24@1127 349 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 350 return -EFAULT;
kaf24@1127 351
kaf24@1127 352 switch ( op.cmd )
kaf24@954 353 {
kaf24@954 354 case EVTCHNOP_open:
kaf24@1127 355 rc = event_channel_open(&op.u.open);
kaf24@1127 356 if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
kaf24@1127 357 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 358 break;
kaf24@954 359
kaf24@954 360 case EVTCHNOP_close:
kaf24@1127 361 rc = event_channel_close(&op.u.close);
kaf24@954 362 break;
kaf24@954 363
kaf24@954 364 case EVTCHNOP_send:
kaf24@1127 365 rc = event_channel_send(op.u.send.local_port);
kaf24@954 366 break;
kaf24@954 367
kaf24@954 368 case EVTCHNOP_status:
kaf24@1127 369 rc = event_channel_status(&op.u.status);
kaf24@1127 370 if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
kaf24@1127 371 rc = -EFAULT;
kaf24@954 372 break;
kaf24@954 373
kaf24@954 374 default:
kaf24@954 375 rc = -ENOSYS;
kaf24@954 376 break;
kaf24@954 377 }
kaf24@954 378
kaf24@954 379 return rc;
kaf24@954 380 }
kaf24@954 381
kaf24@954 382
kaf24@954 383 void destroy_event_channels(struct task_struct *p)
kaf24@954 384 {
kaf24@954 385 int i;
kaf24@954 386 if ( p->event_channel != NULL )
kaf24@954 387 {
kaf24@954 388 for ( i = 0; i < p->max_event_channel; i++ )
kaf24@1127 389 (void)__event_channel_close(p, i);
kaf24@954 390 kfree(p->event_channel);
kaf24@954 391 }
kaf24@954 392 }