direct-io.hg

view tools/x2d2/main.c @ 2956:0cf4902093b4

bitkeeper revision 1.1159.170.12 (4194eb32TtoQmmdoymakhiMQr5rPLg)

Correct typo.
author sos22@douglas.cl.cam.ac.uk
date Fri Nov 12 16:56:18 2004 +0000 (2004-11-12)
parents 42e5ff1b17e1
children 2b25e0010db8
line source
1 #define _GNU_SOURCE
3 #include <sys/types.h>
4 #include <sys/fcntl.h>
5 #include <sys/ioctl.h>
6 #include <sys/mman.h>
7 #include <sys/select.h>
8 #include <sys/socket.h>
9 #include <sys/wait.h>
10 #include <asm/page.h>
11 #include <assert.h>
12 #include <ctype.h>
13 #include <err.h>
14 #include <errno.h>
15 #include <netinet/in.h>
16 #include <printf.h>
17 #include <pthread.h>
18 #include <stdarg.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "minixend.h"
27 #define NETWORK_SCRIPT "/etc/xen/scripts/network"
28 #define VIFBRIDGE_SCRIPT "/etc/xen/scripts/vif-bridge"
30 #define MINIXEND_PORT 5123
32 #define mb() asm volatile ("" ::: "memory")
34 static void send_control_message(int type, int subtype, int id,
35 int size, void *payload,
36 struct domain *target);
38 struct list_head
39 head_domain = LIST_HEAD(&head_domain);
41 static struct list_head
42 head_connection = LIST_HEAD(&head_connection);
44 struct list_head
45 head_console = LIST_HEAD(&head_console);
47 #define foreach_open_connection(d) \
48 foreach_item(d, &head_connection, struct open_connection, connection_list)
50 /* Not modified after initial start up */
51 static struct domain *
52 dom0;
53 unsigned
54 xc_handle;
55 static int
56 listen_fd;
57 int
58 evtchn_fd;
60 static struct list_head
61 head_event_receiver = LIST_HEAD(&head_event_receiver);
63 struct event_receiver {
64 struct list_head list;
65 int id;
66 pthread_cond_t cond;
67 };
69 /* We're protected by the dom0 mutex in here */
70 static struct event_receiver *
71 allocate_event_receiver(struct domain *d)
72 {
73 static int next_message_id;
74 struct event_receiver *work;
76 assert(d == dom0);
77 work = xmalloc(sizeof(*work));
78 work->id = next_message_id++;
79 pthread_cond_init(&work->cond, NULL);
81 list_insert_after(&work->list, &head_event_receiver);
83 return work;
84 }
86 static struct event_receiver *
87 find_event_receiver(int id)
88 {
89 struct event_receiver *work;
90 foreach_item(work, &head_event_receiver, struct event_receiver, list)
91 if (work->id == id)
92 return work;
93 return NULL;
94 }
96 static void
97 release_event_receiver(struct event_receiver *w)
98 {
99 list_remove(&w->list);
100 pthread_cond_destroy(&w->cond);
101 free(w);
102 }
104 /* Send a message to dom0, and then block awaiting a reply. */
105 /* Make sure we don't hold any domain mutexs */
106 static void
107 send_dom0_message_block(control_msg_t *msg)
108 {
109 CONTROL_RING_IDX c;
110 struct event_receiver *er;
111 control_msg_t buf;
113 PRINTF(0, "sending message to dom0 and blocking for reply.\n");
114 pthread_mutex_lock(&dom0->mux);
115 PRINTF(0, "got dom0 lock.\n");
116 er = allocate_event_receiver(dom0);
117 PRINTF(0, "allocated evetn receiver.\n");
118 msg->id = er->id;
119 PRINTF(1, "sending message with id %d\n", msg->id);
120 send_control_message(msg->type, msg->subtype,
121 msg->id, msg->length, msg->msg, dom0);
122 xc_evtchn_send(xc_handle, dom0->control_evtchn);
124 PRINTF(0, "waiting for reply\n");
125 pthread_cond_wait(&er->cond, &dom0->mux);
126 PRINTF(0, "got reply\n");
128 c = dom0->rx_resp_cons % CONTROL_RING_SIZE;
129 memcpy(&buf, &dom0->ctrl_if->rx_ring[c], sizeof(buf));
130 assert(msg->id == buf.id);
131 assert(msg->type == buf.type);
132 assert(msg->subtype == buf.subtype);
133 memcpy(msg, &buf, sizeof(*msg));
134 dom0->rx_resp_cons++;
136 release_event_receiver(er);
138 pthread_mutex_unlock(&dom0->mux);
140 PRINTF(1, "got reply to message with id %d\n", msg->id);
141 }
143 /* Allocate an interdomain event channel. event_ports[0] is the
144 local event port number, event_ports[1] the remote */
145 int
146 allocate_event_channel(struct domain *d, int event_ports[2])
147 {
148 return xc_evtchn_bind_interdomain(xc_handle, DOMID_SELF,
149 d->domid, event_ports,
150 event_ports+1);
151 }
153 static void
154 accept_new_connection(void)
155 {
156 int fd;
157 struct open_connection *oc;
159 fd = accept(listen_fd, NULL, NULL);
160 if (fd < 0)
161 return;
162 oc = xmalloc(sizeof(*oc));
163 oc->fd = fd;
164 oc->state = OC_STATE_CONNECTED;
165 oc->buf_used = 0;
166 oc->buf_allocated = 16;
167 oc->buf = xmalloc(oc->buf_allocated);
168 list_insert_after(&oc->connection_list, &head_connection);
169 }
171 static void
172 closedown_connection(struct open_connection *oc)
173 {
174 close(oc->fd);
175 assert(oc->buf);
176 free(oc->buf);
177 free(oc);
178 }
180 #if 0
181 /* Hackl for the benefit of domain replay */
182 static unsigned
183 report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
184 {
185 if (!do_direct) {
186 int rc;
187 asm("int $0x80" : "=a" (rc)
188 : "0" (264), "b" (ptr), "c" (val), "d" (dom));
189 if (rc < 0) {
190 errno = -rc;
191 rc = -1;
192 }
193 return rc;
194 } else {
195 *ptr = val;
196 return 0;
197 }
198 }
199 #else
200 static unsigned
201 report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
202 {
203 *ptr = val;
204 return 0;
205 }
206 #endif
208 static void
209 send_control_reply(const control_msg_t *msg, struct domain *d)
210 {
211 CONTROL_RING_IDX c;
213 PRINTF(3,"Control reply, type %d:%d, length %d.\n",
214 msg->type, msg->subtype, msg->length);
215 c = d->ctrl_if->tx_resp_prod % CONTROL_RING_SIZE;
216 memcpy(&d->ctrl_if->tx_ring[c], msg, sizeof(*msg));
217 report_work(&d->ctrl_if->tx_resp_prod,
218 d->ctrl_if->tx_resp_prod + 1,
219 d->domid,
220 0);
221 PRINTF(4,"tx_resp_prod %ld.\n", d->ctrl_if->tx_resp_prod);
222 assert(!d->plugged);
223 }
225 static void
226 send_trivial_control_reply(const control_msg_t *msg, struct domain *d)
227 {
228 control_msg_t rep;
230 memset(&rep, 0, sizeof(rep));
231 rep.type = msg->type;
232 rep.subtype = msg->subtype;
233 rep.id = msg->id;
234 send_control_reply(&rep, d);
235 }
237 static void
238 process_console_control_message(control_msg_t *m, struct domain *d)
239 {
240 int off;
241 int r;
243 if (m->subtype != CMSG_CONSOLE_DATA) {
244 warnx("unknown console message subtype %d",
245 m->subtype);
246 return;
247 }
249 if (m->length > 60) {
250 warnx("truncating message from domain %d (was length %d)",
251 d->domid, m->length);
252 m->length = 60;
253 }
254 PRINTF(1, "DOM%d: %.*s\n", d->domid, m->length, m->msg);
255 send_trivial_control_reply(m, d);
257 if (d->cc) {
258 PRINTF(5, "Have a console connection.\n");
259 if (d->cc->state == CC_STATE_CONNECTED) {
260 PRINTF(5, "Console is connected, sending directly.\n");
261 for (off = 0; off < m->length; off += r) {
262 r = write(d->cc->fd, m->msg + off,
263 m->length - off);
264 if (r <= 0) {
265 d->cc->state = CC_STATE_ERROR;
266 break;
267 }
268 }
269 } else {
270 PRINTF(5, "Console not connected, buffering.\n");
271 if (d->cc->buf_allocated == 0) {
272 d->cc->buf_allocated = 60;
273 d->cc->buf = xmalloc(d->cc->buf_allocated);
274 d->cc->buf_used = 0;
275 } else if (d->cc->buf_allocated <
276 d->cc->buf_used + m->length) {
277 d->cc->buf_allocated += 60;
278 d->cc->buf = xrealloc(d->cc->buf,
279 d->cc->buf_allocated);
280 }
281 assert(d->cc->buf_allocated >=
282 d->cc->buf_used + m->length);
283 memcpy(d->cc->buf + d->cc->buf_used,
284 m->msg,
285 m->length);
286 d->cc->buf_used += m->length;
287 }
288 }
289 }
291 static void
292 process_blkif_fe_message(control_msg_t *m, struct domain *d)
293 {
294 switch (m->subtype) {
295 default:
296 warnx("unknown blkif front end message subtype %d",
297 m->subtype);
298 }
299 }
301 static void
302 send_control_message(int type, int subtype, int id,
303 int size, void *payload, struct domain *target)
304 {
305 control_msg_t msg;
306 CONTROL_RING_IDX c;
308 msg.type = type;
309 msg.subtype = subtype;
310 msg.id = id;
311 msg.length = size;
312 memcpy(msg.msg, payload, size);
314 c = target->ctrl_if->rx_req_prod % CONTROL_RING_SIZE;
315 memcpy(&target->ctrl_if->rx_ring[c], &msg, sizeof(msg));
316 report_work(&target->ctrl_if->rx_req_prod,
317 target->ctrl_if->rx_req_prod + 1,
318 target->domid,
319 0);
320 assert(!target->plugged);
321 }
323 /* Procedure for bringing a new netif front end up:
325 -- Front end sends us NETIF_FE_DRIVER_STATUS_CHANGED
326 -- We send back end NETIF_BE_CREATE, wait for a reply
327 -- Back end creates a new netif for us, replies
328 -- We send front end a NETIF_FE_DRIVER_STATUS_CHANGED message saying
329 how many interfaces we've created for it
330 -- We send front end a NETIF_FE_INTERFACE_STATUS_CHANGED for each
331 netif created
332 -- Front end sends us a NETIF_FE_INTERFACE_CONNECT for each netif
333 */
334 static void
335 handle_netif_fe_driver_status_changed(control_msg_t *m,
336 netif_fe_driver_status_changed_t *sh,
337 struct domain *d)
338 {
339 netif_fe_interface_status_changed_t if_s;
340 control_msg_t be_msg;
341 netif_be_create_t *be = (void *)be_msg.msg;
342 int r;
344 switch (sh->status) {
345 case NETIF_DRIVER_STATUS_UP:
346 /* Tell the back end about the new interface coming
347 * up. */
348 if (d->created_netif_backend) {
349 PRINTF(10, "Front end came up twice in dom %d -> reporting no interfaces this time around.\n", d->domid);
350 sh->nr_interfaces = 0;
351 send_control_reply(m, d);
352 send_control_message(CMSG_NETIF_FE,
353 CMSG_NETIF_FE_DRIVER_STATUS_CHANGED,
354 1,
355 sizeof(*sh),
356 sh,
357 d);
358 return;
359 }
360 be_msg.type = CMSG_NETIF_BE;
361 be_msg.subtype = CMSG_NETIF_BE_CREATE;
362 be_msg.id = d->domid;
363 be_msg.length = sizeof(*be);
364 be->domid = d->domid;
365 be->netif_handle = 0;
366 memcpy(be->mac, d->netif_mac, 6);
368 PRINTF(2,"Telling back end about new front end.\n");
369 pthread_mutex_unlock(&d->mux);
370 send_dom0_message_block(&be_msg);
371 pthread_mutex_lock(&d->mux);
372 PRINTF(3,"Done.\n");
374 if (be->status != NETIF_BE_STATUS_OKAY) {
375 /* Uh oh... can't bring back end
376 * up. */
377 sh->nr_interfaces = 0;
378 send_control_reply(m, d);
379 send_control_message(CMSG_NETIF_FE,
380 CMSG_NETIF_FE_DRIVER_STATUS_CHANGED,
381 1,
382 sizeof(*sh),
383 sh,
384 d);
385 return;
386 }
387 d->created_netif_backend = 1;
389 r = our_system(VIFBRIDGE_SCRIPT " up domain=%s mac=%.02x:%.02x:%.02x:%.02x:%.02x:%.02x vif=vif%d.0 bridge=xen-br0",
390 d->name,
391 d->netif_mac[0],
392 d->netif_mac[1],
393 d->netif_mac[2],
394 d->netif_mac[3],
395 d->netif_mac[4],
396 d->netif_mac[5],
397 d->domid);
398 if (r != 0)
399 warn("error %d running " VIFBRIDGE_SCRIPT, r);
401 /* Tell domain how many interfaces it has to deal
402 * with. */
403 sh->nr_interfaces = 1;
404 send_control_reply(m, d);
405 send_control_message(CMSG_NETIF_FE,
406 CMSG_NETIF_FE_DRIVER_STATUS_CHANGED,
407 1,
408 sizeof(*sh),
409 sh,
410 d);
412 PRINTF(2,"Telling front end about its interfaces.\n");
413 if_s.handle = 0;
414 if_s.status = NETIF_INTERFACE_STATUS_DISCONNECTED;
415 send_control_message(CMSG_NETIF_FE,
416 CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED,
417 1,
418 sizeof(if_s),
419 &if_s,
420 d);
421 PRINTF(3,"Done.\n");
423 break;
424 default:
425 warnx("unknown netif status %ld", sh->status);
426 break;
427 }
428 }
430 static void
431 handle_netif_fe_interface_connect(control_msg_t *m,
432 netif_fe_interface_connect_t *ic,
433 struct domain *d)
434 {
435 control_msg_t be_msg;
436 netif_be_connect_t *bmsg = (void *)be_msg.msg;
437 netif_fe_interface_status_changed_t fmsg = {0};
438 int evtchn_ports[2];
439 int r;
441 PRINTF(4, "front end sent us an interface connect message.\n");
442 send_trivial_control_reply(m, d);
444 r = xc_evtchn_bind_interdomain(xc_handle,
445 dom0->domid,
446 d->domid,
447 &evtchn_ports[0],
448 &evtchn_ports[1]);
449 if (r < 0)
450 err(1, "allocating network event channel");
452 be_msg.type = CMSG_NETIF_BE;
453 be_msg.subtype = CMSG_NETIF_BE_CONNECT;
454 be_msg.id = 0;
455 be_msg.length = sizeof(*bmsg);
456 bmsg->domid = d->domid;
457 bmsg->netif_handle = ic->handle;
458 bmsg->tx_shmem_frame = ic->tx_shmem_frame;
459 bmsg->rx_shmem_frame = ic->rx_shmem_frame;
460 bmsg->evtchn = evtchn_ports[0];
462 pthread_mutex_unlock(&d->mux);
463 send_dom0_message_block(&be_msg);
464 pthread_mutex_lock(&d->mux);
466 if (bmsg->status != NETIF_BE_STATUS_OKAY) {
467 PRINTF(2, "error connected backend netif: %ld\n",
468 bmsg->status);
469 abort(); /* Need to handle this */
470 } else {
471 PRINTF(3, "connect backend netif\n");
473 /* Tell the domain that we've connected it up. */
474 fmsg.handle = ic->handle;
475 fmsg.status = NETIF_INTERFACE_STATUS_CONNECTED;
476 fmsg.evtchn = evtchn_ports[1];
477 memcpy(fmsg.mac, d->netif_mac, 6);
479 send_control_message(CMSG_NETIF_FE,
480 CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED,
481 0,
482 sizeof(fmsg),
483 &fmsg,
484 d);
485 }
486 }
488 static void
489 process_netif_fe_message(control_msg_t *m, struct domain *d)
490 {
491 switch (m->subtype) {
492 case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
493 {
494 netif_fe_driver_status_changed_t *sh =
495 (netif_fe_driver_status_changed_t *)m->msg;
496 handle_netif_fe_driver_status_changed(m, sh, d);
497 break;
498 }
499 case CMSG_NETIF_FE_INTERFACE_CONNECT:
500 {
501 netif_fe_interface_connect_t *ic =
502 (netif_fe_interface_connect_t *)m->msg;
503 handle_netif_fe_interface_connect(m, ic, d);
504 break;
505 }
506 default:
507 warnx("unknown netif front end message subtype %d",
508 m->subtype);
509 }
510 }
512 static void
513 process_pdb_be_driver_status_changed_message(control_msg_t *msg,
514 pdb_be_driver_status_changed_t*pe,
515 struct domain *d)
516 {
517 pdb_be_connected_t conn;
518 pdb_fe_new_be_t new_be;
519 int assist_channel[2];
520 int event_channel[2];
521 int r;
523 switch (pe->status) {
524 case PDB_DRIVER_STATUS_UP:
525 PRINTF(4, "creating event channel for PDB device\n");
526 r = allocate_event_channel(d, assist_channel);
527 r |= allocate_event_channel(d, event_channel);
528 if (r < 0)
529 abort(); /* XXX need to handle this */
531 send_trivial_control_reply(msg, d);
533 PRINTF(4, "informing front end of event channel\n");
534 conn.assist_port = assist_channel[1];
535 conn.event_port = event_channel[1];
536 send_control_message(CMSG_PDB_BE,
537 CMSG_PDB_BE_INTERFACE_CONNECTED,
538 0,
539 sizeof(conn),
540 &conn,
541 d);
543 PRINTF(4, "informing back end of front end\n");
544 new_be.domain = d->domid;
545 new_be.assist_evtchn = assist_channel[0];
546 new_be.event_evtchn = event_channel[0];
547 new_be.assist_frame = pe->assist_page;
548 new_be.event_frame = pe->event_page;
549 send_control_message(CMSG_PDB_FE,
550 CMSG_PDB_FE_NEW_BE,
551 0,
552 sizeof(new_be),
553 &new_be,
554 dom0);
555 break;
556 default:
557 warnx("unknown pdb status %d", pe->status);
558 }
559 }
561 static void
562 process_pdb_be_message(control_msg_t *msg, struct domain *d)
563 {
564 switch (msg->subtype) {
565 case CMSG_PDB_BE_DRIVER_STATUS_CHANGED:
566 {
567 pdb_be_driver_status_changed_t *pe =
568 (pdb_be_driver_status_changed_t *)msg->msg;
569 process_pdb_be_driver_status_changed_message(msg, pe, d);
570 break;
571 }
572 default:
573 warnx("unknown pdb back end message subtype %d",
574 msg->subtype);
575 }
576 }
578 static void
579 process_control_message(control_msg_t *msg, struct domain *d)
580 {
581 control_msg_t m;
583 /* Don't want a malicous domain messing us about, so copy the
584 control mesasge into a local buffer. */
585 memcpy(&m, msg, sizeof(m));
586 switch (m.type) {
587 case CMSG_CONSOLE:
588 process_console_control_message(&m, d);
589 break;
590 case CMSG_BLKIF_FE:
591 process_blkif_fe_message(&m, d);
592 break;
593 case CMSG_NETIF_FE:
594 process_netif_fe_message(&m, d);
595 break;
596 case CMSG_PDB_BE:
597 process_pdb_be_message(&m, d);
598 break;
599 default:
600 warnx("unknown control message type %d", m.type);
601 }
602 }
604 static void
605 domain_did_control_event(struct domain *d)
606 {
607 CONTROL_RING_IDX c;
609 /* Pick up and process control ring messages. */
610 while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
611 c = d->tx_req_cons % CONTROL_RING_SIZE;
612 process_control_message(&d->ctrl_if->tx_ring[c], d);
613 d->tx_req_cons++;
614 assert(d->tx_req_cons <= d->ctrl_if->tx_req_prod);
615 PRINTF(5, "req_cons %ld, req_prod %ld.\n",
616 d->tx_req_cons, d->ctrl_if->tx_req_prod);
617 }
619 /* Take any replies off, and discard them. */
620 if (d->rx_resp_cons != d->ctrl_if->rx_resp_prod)
621 PRINTF(1, "discard %ld events\n",
622 d->ctrl_if->rx_resp_prod -
623 d->rx_resp_cons);
624 d->rx_resp_cons = d->ctrl_if->rx_resp_prod;
625 }
627 /* This is the main function for domain control threads */
628 void *
629 domain_thread_func(void *D)
630 {
631 struct domain *d = D;
632 int r;
633 CONTROL_RING_IDX old_resp_prod, old_req_prod;
635 pthread_mutex_lock(&d->mux);
636 for (;;) {
637 pthread_cond_wait(&d->cond, &d->mux);
639 old_resp_prod = d->ctrl_if->tx_resp_prod;
640 old_req_prod = d->ctrl_if->rx_req_prod;
642 domain_did_control_event(d);
643 if (d->cc && d->cc->in_buf_used != 0 && d->plugged == 0) {
644 r = d->cc->in_buf_used;
645 if (r > 60)
646 r = 60;
647 PRINTF(1, "Sending to domain: %.*s\n",
648 r, d->cc->in_buf);
649 send_control_message(CMSG_CONSOLE,
650 CMSG_CONSOLE_DATA,
651 0,
652 r,
653 d->cc->in_buf,
654 d);
655 memmove(d->cc->in_buf, d->cc->in_buf + r,
656 d->cc->in_buf_used - r);
657 d->cc->in_buf_used -= r;
658 }
660 if (d->ctrl_if->tx_resp_prod != old_resp_prod ||
661 d->ctrl_if->rx_req_prod != old_req_prod)
662 xc_evtchn_send(xc_handle, d->control_evtchn);
663 }
664 }
666 /* This is the only thing you can do with a domain structure if you're
667 not in the thread which controls that domain. Domain 0 is
668 special. */
669 void
670 signal_domain(struct domain *d)
671 {
672 CONTROL_RING_IDX c;
673 int id;
674 struct event_receiver *evt;
676 pthread_mutex_lock(&d->mux);
677 if (d == dom0) {
678 /* Take events off of dom0's control ring, and send
679 them to the event receivers. */
680 while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
681 c = d->tx_req_cons % CONTROL_RING_SIZE;
682 id = d->ctrl_if->tx_ring[c].id;
683 evt = find_event_receiver(id);
684 if (evt != NULL) {
685 PRINTF(1, "delivering event id %d\n", evt->id);
686 pthread_cond_broadcast(&evt->cond);
687 pthread_mutex_unlock(&d->mux);
688 pthread_yield();
689 pthread_mutex_lock(&d->mux);
690 } else {
691 warnx("unexpected message id %d discarded",
692 id);
693 d->tx_req_cons++;
694 }
695 }
696 while (d->rx_resp_cons != d->ctrl_if->rx_resp_prod) {
697 c = d->rx_resp_cons % CONTROL_RING_SIZE;
698 id = d->ctrl_if->rx_ring[c].id;
699 evt = find_event_receiver(id);
700 if (evt != NULL) {
701 PRINTF(1, "delivering event rep id %d\n", evt->id);
702 pthread_cond_broadcast(&evt->cond);
703 pthread_mutex_unlock(&d->mux);
704 pthread_yield();
705 pthread_mutex_lock(&d->mux);
706 } else {
707 warnx("unexpected message reply id %d discarded",
708 id);
709 d->rx_resp_cons++;
710 }
711 }
712 } else {
713 if (d->plugged) {
714 d->event_pending = 1;
715 } else {
716 pthread_cond_broadcast(&d->cond);
717 }
718 }
719 pthread_mutex_unlock(&d->mux);
720 }
722 static void
723 handle_evtchn_event(void)
724 {
725 short port;
726 struct domain *d;
728 read(evtchn_fd, &port, sizeof(short));
729 write(evtchn_fd, &port, sizeof(short));
730 foreach_domain (d) {
731 if (d->control_evtchn == port) {
732 signal_domain(d);
733 return;
734 }
735 }
736 warnx("got an event on an unknown port %d", port);
737 }
739 void *
740 map_domain_mem(struct domain *d, unsigned long mfn)
741 {
742 return xc_map_foreign_range(xc_handle, d->domid,
743 PAGE_SIZE, PROT_READ | PROT_WRITE,
744 mfn);
745 }
747 static void
748 handle_console_event(struct console_connection *cc)
749 {
750 int r;
751 int fd;
753 switch (cc->state) {
754 case CC_STATE_ERROR:
755 /* Errors shouldn't get here. */
756 abort();
757 case CC_STATE_PENDING:
758 fd = accept(cc->fd, NULL, NULL);
759 if (fd >= 0) {
760 PRINTF(3, "Accepted console connection for domain %d",
761 cc->dom->domid);
762 close(cc->fd);
763 cc->fd = fd;
764 cc->state = CC_STATE_CONNECTED;
765 while (cc->buf_used != 0) {
766 r = write(cc->fd,
767 cc->buf,
768 cc->buf_used);
769 if (r <= 0) {
770 cc->state = CC_STATE_ERROR;
771 break;
772 }
773 memmove(cc->buf,
774 cc->buf + r,
775 cc->buf_used - r);
776 cc->buf_used -= r;
777 }
778 free(cc->buf);
779 cc->buf = NULL;
780 cc->buf_allocated = 0;
781 } else {
782 PRINTF(1, "error %s accepting console", strerror(errno));
783 }
784 pthread_mutex_unlock(&cc->dom->mux);
785 break;
786 case CC_STATE_CONNECTED:
787 if (cc->in_buf_allocated == 0) {
788 assert(cc->in_buf_used == 0);
789 cc->in_buf_allocated = 128;
790 cc->in_buf = xmalloc(cc->in_buf_allocated);
791 }
792 if (cc->in_buf_used == cc->in_buf_allocated) {
793 cc->in_buf_allocated *= 2;
794 cc->in_buf = xrealloc(cc->in_buf, cc->in_buf_allocated);
795 }
796 r = read(cc->fd, cc->in_buf + cc->in_buf_used,
797 cc->in_buf_allocated - cc->in_buf_used);
798 if (r <= 0) {
799 cc->state = CC_STATE_ERROR;
800 } else {
801 cc->in_buf_used += r;
802 }
803 pthread_mutex_unlock(&cc->dom->mux);
804 signal_domain(cc->dom);
805 break;
806 }
807 }
809 static void
810 handle_connection_event(struct open_connection *oc)
811 {
812 int r;
814 /* We know that some amount of data is ready and waiting for
815 us. Slurp it in. */
816 if (oc->buf_used == oc->buf_allocated) {
817 oc->buf_allocated *= 2;
818 oc->buf = xrealloc(oc->buf, oc->buf_allocated);
819 }
820 r = read(oc->fd, oc->buf + oc->buf_used,
821 oc->buf_allocated - oc->buf_used);
822 if (r < 0) {
823 warn("reading command from remote");
824 oc->state = OC_STATE_ERROR;
825 } else if (r == 0) {
826 warnx("reading command from remote");
827 oc->state = OC_STATE_ERROR;
828 } else {
829 oc->buf_used += r;
830 if (strchr(oc->buf, '\n'))
831 oc->state = OC_STATE_COMMAND_PENDING;
832 }
833 }
835 static void
836 get_and_process_event(void)
837 {
838 fd_set read_fds, except_fds;
839 struct open_connection *oc;
840 struct console_connection *cc;
841 int max_fd = listen_fd;
842 int r;
843 struct list_head *li, *temp_li;
845 FD_ZERO(&read_fds);
846 FD_ZERO(&except_fds);
847 FD_SET(listen_fd, &read_fds);
848 FD_SET(evtchn_fd, &read_fds);
849 if (evtchn_fd > max_fd)
850 max_fd = evtchn_fd;
851 foreach_open_connection(oc) {
852 FD_SET(oc->fd, &read_fds);
853 FD_SET(oc->fd, &except_fds);
854 if (oc->fd > max_fd)
855 max_fd = oc->fd;
856 }
857 foreach_console_connection(cc) {
858 FD_SET(cc->fd, &read_fds);
859 FD_SET(cc->fd, &except_fds);
860 if (cc->fd > max_fd)
861 max_fd = cc->fd;
862 }
864 r = select(max_fd + 1, &read_fds, NULL, &except_fds, NULL);
865 if (r < 0)
866 err(1, "select");
867 if (FD_ISSET(listen_fd, &read_fds)) {
868 accept_new_connection();
869 } else if (FD_ISSET(evtchn_fd, &read_fds))
870 handle_evtchn_event();
873 foreach_open_connection(oc) {
874 if (FD_ISSET(oc->fd, &read_fds))
875 handle_connection_event(oc);
876 if (FD_ISSET(oc->fd, &except_fds))
877 oc->state = OC_STATE_ERROR;
878 }
879 list_foreach_safe(&head_console, li, temp_li) {
880 cc = list_item(li, struct console_connection, list);
881 if (FD_ISSET(cc->fd, &read_fds))
882 handle_console_event(cc);
883 if (FD_ISSET(cc->fd, &except_fds) ||
884 cc->state == CC_STATE_ERROR) {
885 PRINTF(1, "Cleaning up console connection");
886 cc->dom->cc = NULL;
887 list_remove(&cc->list);
888 close(cc->fd);
889 if (cc->buf_allocated != 0)
890 free(cc->buf);
891 if (cc->in_buf_allocated != 0)
892 free(cc->in_buf);
893 free(cc);
894 }
895 }
897 /* Run pending stuff on the open connections. */
898 list_foreach_safe(&head_connection, li, temp_li) {
899 oc = list_item(li, struct open_connection, connection_list);
900 switch (oc->state) {
901 case OC_STATE_ERROR:
902 list_remove(&oc->connection_list);
903 closedown_connection(oc);
904 break;
905 case OC_STATE_COMMAND_PENDING:
906 process_command(oc);
907 break;
908 case OC_STATE_CONNECTED:
909 /* Don't need to do anything */
910 break;
911 }
912 }
913 }
915 static int
916 start_listening(void)
917 {
918 int sock;
919 struct sockaddr_in inaddr;
921 sock = socket(PF_INET, SOCK_STREAM, 0);
922 if (sock < 0)
923 err(1, "creating socket");
924 memset(&inaddr, 0, sizeof(inaddr));
925 inaddr.sin_family = AF_INET;
926 inaddr.sin_port = htons(MINIXEND_PORT);
928 if (bind(sock, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
929 err(1, "binding to port %d", MINIXEND_PORT);
930 if (listen(sock, 5) < 0)
931 err(1, "listening for connections");
933 return sock;
934 }
936 static struct domain *
937 find_dom0(void)
938 {
939 int r;
940 xc_dominfo_t info;
941 struct domain *work;
943 r = xc_domain_getinfo(xc_handle, 0, 1, &info);
944 if (r < 0)
945 err(1, "getting domain 0 information");
946 work = xmalloc(sizeof(*work));
947 work->control_evtchn = 2;
948 if (ioctl(evtchn_fd, EVTCHN_BIND, 2) < 0)
949 err(1, "binding to domain 0 control event channel");
951 work->domid = 0;
952 work->name = xstrdup("dom0");
953 work->mem_kb = info.max_memkb;
954 work->state = DOM_STATE_RUNNING;
955 work->shared_info_mfn = info.shared_info_frame;
957 work->shared_info = map_domain_mem(work, info.shared_info_frame);
958 work->ctrl_if = (control_if_t *)((unsigned)work->shared_info + 2048);
959 work->tx_req_cons = work->ctrl_if->tx_req_prod;
960 work->rx_resp_cons = work->ctrl_if->rx_resp_prod;
962 pthread_mutex_init(&work->mux, NULL);
963 pthread_cond_init(&work->cond, NULL);
965 list_insert_after(&work->domain_list, &head_domain);
967 return work;
968 }
970 int
971 main(int argc, char *argv[])
972 {
973 int r;
975 r = our_system(NETWORK_SCRIPT " start antispoof=no");
976 if (r < 0)
977 err(1, "running " NETWORK_SCRIPT);
978 if (!WIFEXITED(r)) {
979 if (WIFSIGNALED(r)) {
980 errx(1, NETWORK_SCRIPT " killed by signal %d",
981 WTERMSIG(r));
982 }
983 errx(1, NETWORK_SCRIPT " terminated abnormally");
984 }
985 if (WEXITSTATUS(r) != 0)
986 errx(1, NETWORK_SCRIPT " returned error status %d",
987 WEXITSTATUS(r));
989 xc_handle = xc_interface_open();
991 listen_fd = start_listening();
993 evtchn_fd = open("/dev/xen/evtchn", O_RDWR);
994 if (evtchn_fd < 0)
995 err(1, "openning /dev/xen/evtchn");
997 dom0 = find_dom0();
999 while (1) {
1000 get_and_process_event();
1002 PRINTF(5, "Dom0 ring state:\n");
1003 PRINTF(5, "RX: req_prod %ld, resp_prod %ld, resp_cons %ld\n",
1004 dom0->ctrl_if->rx_req_prod,
1005 dom0->ctrl_if->rx_resp_prod,
1006 dom0->rx_resp_cons);
1007 PRINTF(5, "TX: req_prod %ld, resp_prod %ld, req_cons %ld\n",
1008 dom0->ctrl_if->tx_req_prod,
1009 dom0->ctrl_if->tx_resp_prod,
1010 dom0->tx_req_cons);
1013 return 0;