ia64/xen-unstable

annotate xen/common/event_channel.c @ 1145:15b958f52da1

bitkeeper revision 1.764.1.1 (4048c0e77koAHUIwNvQFG76iV0Alrg)

evtchn.h, control_if.h:
new file
Many files:
Bidirectional consoles for domains >0. Run 'tools/xend/xend' and telnet to the port printed by xc_dom_create.py. (eg. 'telnet localhost 9600').
.del-xen_read_console.c~2a30ac556d6835c7:
Delete: tools/misc/xen_read_console.c
author kaf24@scramble.cl.cam.ac.uk
date Fri Mar 05 18:03:19 2004 +0000 (2004-03-05)
parents 5b6243a7571b
children 5c59473e9416
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 if ( dom1 == DOMID_SELF )
kaf24@1129 96 dom1 = current->domain;
kaf24@1129 97 if ( dom2 == DOMID_SELF )
kaf24@1135 98 dom2 = current->domain;
kaf24@1127 99
kaf24@1129 100 if ( ((p1 = find_domain_by_id(dom1)) == NULL) ||
kaf24@1129 101 ((p2 = find_domain_by_id(dom2)) == NULL) )
kaf24@1127 102 {
kaf24@1129 103 if ( p1 != NULL )
kaf24@1129 104 put_task_struct(p1);
kaf24@1127 105 return -ESRCH;
kaf24@1127 106 }
kaf24@1127 107
kaf24@1127 108 /* Avoid deadlock by first acquiring lock of domain with smaller id. */
kaf24@1129 109 if ( dom1 < dom2 )
kaf24@954 110 {
kaf24@1129 111 spin_lock(&p1->event_channel_lock);
kaf24@1129 112 spin_lock(&p2->event_channel_lock);
kaf24@954 113 }
kaf24@954 114 else
kaf24@954 115 {
kaf24@1135 116 if ( p1 != p2 )
kaf24@1135 117 spin_lock(&p2->event_channel_lock);
kaf24@1129 118 spin_lock(&p1->event_channel_lock);
kaf24@954 119 }
kaf24@954 120
kaf24@1129 121 if ( (port1 = get_free_port(p1)) < 0 )
kaf24@954 122 {
kaf24@1129 123 rc = port1;
kaf24@1127 124 goto out;
kaf24@954 125 }
kaf24@954 126
kaf24@1129 127 if ( (port2 = get_free_port(p2)) < 0 )
kaf24@954 128 {
kaf24@1129 129 rc = port2;
kaf24@1127 130 goto out;
kaf24@1127 131 }
kaf24@954 132
kaf24@1129 133 p1->event_channel[port1].remote_dom = p2;
kaf24@1129 134 p1->event_channel[port1].remote_port = (u16)port2;
kaf24@1129 135 p1->event_channel[port1].state = ECS_CONNECTED;
kaf24@954 136
kaf24@1129 137 p2->event_channel[port2].remote_dom = p1;
kaf24@1129 138 p2->event_channel[port2].remote_port = (u16)port1;
kaf24@1129 139 p2->event_channel[port2].state = ECS_CONNECTED;
kaf24@1127 140
kaf24@1138 141 /* Ensure that the disconnect signal is not asserted. */
kaf24@1138 142 clear_bit(port1, &p1->shared_info->event_channel_disc[0]);
kaf24@1138 143 clear_bit(port2, &p2->shared_info->event_channel_disc[0]);
kaf24@1138 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@1135 151 if ( p1 != p2 )
kaf24@1135 152 spin_unlock(&p2->event_channel_lock);
kaf24@1127 153
kaf24@1129 154 put_task_struct(p1);
kaf24@1129 155 put_task_struct(p2);
kaf24@1127 156
kaf24@1129 157 open->port1 = port1;
kaf24@1129 158 open->port2 = port2;
kaf24@954 159
kaf24@954 160 return rc;
kaf24@954 161 }
kaf24@954 162
kaf24@954 163
kaf24@1129 164 static long __event_channel_close(struct task_struct *p1, int port1)
kaf24@954 165 {
kaf24@1129 166 struct task_struct *p2 = NULL;
kaf24@1129 167 event_channel_t *chn1, *chn2;
kaf24@1129 168 int port2;
kaf24@1133 169 unsigned long cpu_mask = 0;
kaf24@954 170 long rc = 0;
kaf24@954 171
kaf24@954 172 again:
kaf24@1129 173 spin_lock(&p1->event_channel_lock);
kaf24@954 174
kaf24@1129 175 chn1 = p1->event_channel;
kaf24@954 176
kaf24@1129 177 if ( (port1 < 0) || (port1 >= p1->max_event_channel) ||
kaf24@1129 178 (chn1[port1].state == ECS_FREE) )
kaf24@954 179 {
kaf24@954 180 rc = -EINVAL;
kaf24@954 181 goto out;
kaf24@954 182 }
kaf24@954 183
kaf24@1129 184 if ( chn1[port1].state == ECS_CONNECTED )
kaf24@954 185 {
kaf24@1129 186 if ( p2 == NULL )
kaf24@954 187 {
kaf24@1129 188 p2 = chn1[port1].remote_dom;
kaf24@1129 189 get_task_struct(p2);
kaf24@1127 190
kaf24@1129 191 if ( p1->domain < p2->domain )
kaf24@954 192 {
kaf24@1129 193 spin_lock(&p2->event_channel_lock);
kaf24@954 194 }
kaf24@1135 195 else if ( p1 != p2 )
kaf24@954 196 {
kaf24@1129 197 spin_unlock(&p1->event_channel_lock);
kaf24@1129 198 spin_lock(&p2->event_channel_lock);
kaf24@954 199 goto again;
kaf24@954 200 }
kaf24@954 201 }
kaf24@1129 202 else if ( p2 != chn1[port1].remote_dom )
kaf24@954 203 {
kaf24@954 204 rc = -EINVAL;
kaf24@954 205 goto out;
kaf24@954 206 }
kaf24@954 207
kaf24@1129 208 chn2 = p2->event_channel;
kaf24@1129 209 port2 = chn1[port1].remote_port;
kaf24@954 210
kaf24@1129 211 if ( port2 >= p2->max_event_channel )
kaf24@1127 212 BUG();
kaf24@1129 213 if ( chn2[port2].state != ECS_CONNECTED )
kaf24@1127 214 BUG();
kaf24@1129 215 if ( chn2[port2].remote_dom != p1 )
kaf24@1127 216 BUG();
kaf24@954 217
kaf24@1133 218 chn2[port2].state = ECS_DISCONNECTED;
kaf24@1129 219 chn2[port2].remote_dom = NULL;
kaf24@1129 220 chn2[port2].remote_port = 0xFFFF;
kaf24@1127 221
kaf24@1129 222 cpu_mask |= set_event_disc(p2, port2);
kaf24@954 223 }
kaf24@954 224
kaf24@1129 225 chn1[port1].state = ECS_FREE;
kaf24@1129 226 chn1[port1].remote_dom = NULL;
kaf24@1129 227 chn1[port1].remote_port = 0xFFFF;
kaf24@954 228
kaf24@1133 229 cpu_mask |= set_event_disc(p1, port1);
kaf24@1133 230 guest_event_notify(cpu_mask);
kaf24@1133 231
kaf24@954 232 out:
kaf24@1129 233 if ( p2 != NULL )
kaf24@954 234 {
kaf24@1135 235 if ( p1 != p2 )
kaf24@1135 236 spin_unlock(&p2->event_channel_lock);
kaf24@1129 237 put_task_struct(p2);
kaf24@954 238 }
kaf24@954 239
kaf24@1145 240 spin_unlock(&p1->event_channel_lock);
kaf24@1145 241
kaf24@954 242 return rc;
kaf24@954 243 }
kaf24@954 244
kaf24@954 245
kaf24@1127 246 static long event_channel_close(evtchn_close_t *close)
kaf24@1127 247 {
kaf24@1129 248 struct task_struct *p;
kaf24@1127 249 long rc;
kaf24@1129 250 domid_t dom = close->dom;
kaf24@1127 251
kaf24@1129 252 if ( dom == DOMID_SELF )
kaf24@1129 253 dom = current->domain;
kaf24@1127 254 else if ( !IS_PRIV(current) )
kaf24@1127 255 return -EPERM;
kaf24@1127 256
kaf24@1129 257 if ( (p = find_domain_by_id(dom)) == NULL )
kaf24@1127 258 return -ESRCH;
kaf24@1127 259
kaf24@1129 260 rc = __event_channel_close(p, close->port);
kaf24@1127 261
kaf24@1129 262 put_task_struct(p);
kaf24@1127 263 return rc;
kaf24@1127 264 }
kaf24@1127 265
kaf24@1127 266
kaf24@1127 267 static long event_channel_send(int lport)
kaf24@954 268 {
kaf24@954 269 struct task_struct *lp = current, *rp;
kaf24@1127 270 int rport;
kaf24@954 271 unsigned long cpu_mask;
kaf24@954 272
kaf24@954 273 spin_lock(&lp->event_channel_lock);
kaf24@954 274
kaf24@1127 275 if ( unlikely(lport < 0) ||
kaf24@1127 276 unlikely(lport >= lp->max_event_channel) ||
kaf24@1127 277 unlikely(lp->event_channel[lport].state != ECS_CONNECTED) )
kaf24@954 278 {
kaf24@954 279 spin_unlock(&lp->event_channel_lock);
kaf24@954 280 return -EINVAL;
kaf24@954 281 }
kaf24@954 282
kaf24@1127 283 rp = lp->event_channel[lport].remote_dom;
kaf24@1127 284 rport = lp->event_channel[lport].remote_port;
kaf24@1127 285
kaf24@1127 286 get_task_struct(rp);
kaf24@954 287
kaf24@954 288 spin_unlock(&lp->event_channel_lock);
kaf24@954 289
kaf24@1127 290 cpu_mask = set_event_pending(rp, rport);
kaf24@1127 291 guest_event_notify(cpu_mask);
kaf24@954 292
kaf24@954 293 put_task_struct(rp);
kaf24@1127 294
kaf24@954 295 return 0;
kaf24@954 296 }
kaf24@954 297
kaf24@954 298
kaf24@1127 299 static long event_channel_status(evtchn_status_t *status)
kaf24@954 300 {
kaf24@1129 301 struct task_struct *p;
kaf24@1129 302 domid_t dom = status->dom1;
kaf24@1129 303 int port = status->port1;
kaf24@1129 304 event_channel_t *chn;
kaf24@1127 305
kaf24@1129 306 if ( dom == DOMID_SELF )
kaf24@1129 307 dom = current->domain;
kaf24@1127 308 else if ( !IS_PRIV(current) )
kaf24@1127 309 return -EPERM;
kaf24@1127 310
kaf24@1129 311 if ( (p = find_domain_by_id(dom)) == NULL )
kaf24@1127 312 return -ESRCH;
kaf24@954 313
kaf24@1129 314 spin_lock(&p->event_channel_lock);
kaf24@954 315
kaf24@1129 316 chn = p->event_channel;
kaf24@954 317
kaf24@1129 318 if ( (port < 0) || (port >= p->max_event_channel) )
kaf24@954 319 {
kaf24@1129 320 spin_unlock(&p->event_channel_lock);
kaf24@1127 321 return -EINVAL;
kaf24@1127 322 }
kaf24@1127 323
kaf24@1129 324 switch ( chn[port].state )
kaf24@1127 325 {
kaf24@1127 326 case ECS_FREE:
kaf24@1127 327 status->status = EVTCHNSTAT_closed;
kaf24@1127 328 break;
kaf24@1133 329 case ECS_DISCONNECTED:
kaf24@1127 330 status->status = EVTCHNSTAT_disconnected;
kaf24@1127 331 break;
kaf24@1127 332 case ECS_CONNECTED:
kaf24@1127 333 status->status = EVTCHNSTAT_connected;
kaf24@1129 334 status->dom2 = chn[port].remote_dom->domain;
kaf24@1129 335 status->port2 = chn[port].remote_port;
kaf24@1127 336 break;
kaf24@1127 337 default:
kaf24@1127 338 BUG();
kaf24@954 339 }
kaf24@954 340
kaf24@1129 341 spin_unlock(&p->event_channel_lock);
kaf24@1127 342 return 0;
kaf24@954 343 }
kaf24@954 344
kaf24@954 345
kaf24@1127 346 long do_event_channel_op(evtchn_op_t *uop)
kaf24@954 347 {
kaf24@954 348 long rc;
kaf24@1127 349 evtchn_op_t op;
kaf24@954 350
kaf24@1127 351 if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
kaf24@1127 352 return -EFAULT;
kaf24@1127 353
kaf24@1127 354 switch ( op.cmd )
kaf24@954 355 {
kaf24@954 356 case EVTCHNOP_open:
kaf24@1127 357 rc = event_channel_open(&op.u.open);
kaf24@1127 358 if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
kaf24@1127 359 rc = -EFAULT; /* Cleaning up here would be a mess! */
kaf24@954 360 break;
kaf24@954 361
kaf24@954 362 case EVTCHNOP_close:
kaf24@1127 363 rc = event_channel_close(&op.u.close);
kaf24@954 364 break;
kaf24@954 365
kaf24@954 366 case EVTCHNOP_send:
kaf24@1127 367 rc = event_channel_send(op.u.send.local_port);
kaf24@954 368 break;
kaf24@954 369
kaf24@954 370 case EVTCHNOP_status:
kaf24@1127 371 rc = event_channel_status(&op.u.status);
kaf24@1127 372 if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
kaf24@1127 373 rc = -EFAULT;
kaf24@954 374 break;
kaf24@954 375
kaf24@954 376 default:
kaf24@954 377 rc = -ENOSYS;
kaf24@954 378 break;
kaf24@954 379 }
kaf24@954 380
kaf24@954 381 return rc;
kaf24@954 382 }
kaf24@954 383
kaf24@954 384
kaf24@954 385 void destroy_event_channels(struct task_struct *p)
kaf24@954 386 {
kaf24@954 387 int i;
kaf24@954 388 if ( p->event_channel != NULL )
kaf24@954 389 {
kaf24@954 390 for ( i = 0; i < p->max_event_channel; i++ )
kaf24@1127 391 (void)__event_channel_close(p, i);
kaf24@954 392 kfree(p->event_channel);
kaf24@954 393 }
kaf24@954 394 }