/* This is the routine which handles console output (ie. stdout). */ static void console_output(struct virtqueue *vq) { unsigned int head, out, in; struct iovec iov[vq->vring.num]; /* We usually wait in here, for the Guest to give us something. */ head = wait_for_vq_desc(vq, iov, &out, &in); if (in) errx(1, "Input buffers in console output queue?"); /* writev can return a partial write, so we loop here. */ while (!iov_empty(iov, out)) { int len = writev(STDOUT_FILENO, iov, out); if (len <= 0) { warn("Write to stdout gave %i (%d)", len, errno); break; } iov_consume(iov, out, len); } /* * We're finished with that buffer: if we're going to sleep, * wait_for_vq_desc() will prod the Guest with an interrupt. */ add_used(vq, head, 0); }
void *consout(void *arg) { char *line, *consline, *outline; static struct scatterlist out[] = { {NULL, sizeof(outline)}, }; static struct scatterlist in[] = { {NULL, sizeof(line)}, }; static struct scatterlist iov[32]; struct virtio_threadarg *a = arg; static unsigned int inlen, outlen, conslen; struct virtqueue *v = a->arg->virtio; fprintf(stderr, "talk thread ..\n"); uint16_t head, gaveit = 0, gotitback = 0; uint32_t vv; int i; int num; if (debug) { fprintf(stderr, "----------------------- TT a %p\n", a); fprintf(stderr, "talk thread ttargs %x v %x\n", a, v); } for(num = 0;;num++) { //int debug = 1; /* host: use any buffers we should have been sent. */ head = wait_for_vq_desc(v, iov, &outlen, &inlen); if (debug) fprintf(stderr, "CCC: vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback); for(i = 0; debug && i < outlen + inlen; i++) fprintf(stderr, "CCC: v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length); /* host: if we got an output buffer, just output it. */ for(i = 0; i < outlen; i++) { num++; int j; if (debug) { fprintf(stderr, "CCC: IOV length is %d\n", iov[i].length); } for (j = 0; j < iov[i].length; j++) printf("%c", ((char *)iov[i].v)[j]); } fflush(stdout); if (debug) fprintf(stderr, "CCC: outlen is %d; inlen is %d\n", outlen, inlen); /* host: fill in the writeable buffers. */ /* why we're getting these I don't know. */ for (i = outlen; i < outlen + inlen; i++) { if (debug) fprintf(stderr, "CCC: send back empty writeable"); iov[i].length = 0; } if (debug) fprintf(stderr, "CCC: call add_used\n"); /* host: now ack that we used them all. */ add_used(v, head, outlen+inlen); if (debug) fprintf(stderr, "CCC: DONE call add_used\n"); } fprintf(stderr, "All done\n"); return NULL; }
/* This is the routine which handles console input (ie. stdin). */ static void console_input(struct virtqueue *vq) { int len; unsigned int head, in_num, out_num; struct console_abort *abort = vq->dev->priv; struct iovec iov[vq->vring.num]; /* Make sure there's a descriptor available. */ head = wait_for_vq_desc(vq, iov, &out_num, &in_num); if (out_num) errx(1, "Output buffers in console in queue?"); /* Read into it. This is where we usually wait. */ len = readv(STDIN_FILENO, iov, in_num); if (len <= 0) { /* Ran out of input? */ warnx("Failed to get console input, ignoring console."); /* * For simplicity, dying threads kill the whole Launcher. So * just nap here. */ for (;;) pause(); } /* Tell the Guest we used a buffer. */ add_used_and_trigger(vq, head, len); /* * Three ^C within one second? Exit. * * This is such a hack, but works surprisingly well. Each ^C has to * be in a buffer by itself, so they can't be too fast. But we check * that we get three within about a second, so they can't be too * slow. */ if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { abort->count = 0; return; } abort->count++; if (abort->count == 1) gettimeofday(&abort->start, NULL); else if (abort->count == 3) { struct timeval now; gettimeofday(&now, NULL); /* Kill all Launcher processes with SIGINT, like normal ^C */ if (now.tv_sec <= abort->start.tv_sec+1) kill(0, SIGINT); abort->count = 0; } }
static void net_output(struct virtqueue *vq) { struct net_info *net_info = vq->dev->priv; unsigned int head, out, in; struct iovec iov[vq->vring.num]; head = wait_for_vq_desc(vq, iov, &out, &in); if (in) errx(1, "Input buffers in net output queue?"); if (writev(net_info->tunfd, iov, out) < 0) warnx("Write to tun failed (%d)?", errno); add_used(vq, head, 0); }
static void net_input(struct virtqueue *vq) { int len; unsigned int head, out, in; struct iovec iov[vq->vring.num]; struct net_info *net_info = vq->dev->priv; head = wait_for_vq_desc(vq, iov, &out, &in); if (out) errx(1, "Output buffers in net input queue?"); if (vq->pending_used && will_block(net_info->tunfd)) trigger_irq(vq); len = readv(net_info->tunfd, iov, in); if (len <= 0) warn("Failed to read from tun (%d).", errno); add_used(vq, head, len); }
static void console_input(struct virtqueue *vq) { int len; unsigned int head, in_num, out_num; struct console_abort *abort = vq->dev->priv; struct iovec iov[vq->vring.num]; head = wait_for_vq_desc(vq, iov, &out_num, &in_num); if (out_num) errx(1, "Output buffers in console in queue?"); len = readv(STDIN_FILENO, iov, in_num); if (len <= 0) { warnx("Failed to get console input, ignoring console."); for (;;) pause(); } add_used_and_trigger(vq, head, len); if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) { abort->count = 0; return; } abort->count++; if (abort->count == 1) gettimeofday(&abort->start, NULL); else if (abort->count == 3) { struct timeval now; gettimeofday(&now, NULL); if (now.tv_sec <= abort->start.tv_sec+1) kill(0, SIGINT); abort->count = 0; } }
static void console_output(struct virtqueue *vq) { unsigned int head, out, in; struct iovec iov[vq->vring.num]; head = wait_for_vq_desc(vq, iov, &out, &in); if (in) errx(1, "Input buffers in console output queue?"); while (!iov_empty(iov, out)) { int len = writev(STDOUT_FILENO, iov, out); if (len <= 0) { warn("Write to stdout gave %i (%d)", len, errno); break; } iov_consume(iov, out, len); } add_used(vq, head, 0); }
static void net_output(struct virtqueue *vq) { struct net_info *net_info = vq->dev->priv; unsigned int head, out, in; struct iovec iov[vq->vring.num]; /* We usually wait in here for the Guest to give us a packet. */ head = wait_for_vq_desc(vq, iov, &out, &in); if (in) errx(1, "Input buffers in net output queue?"); /* * Send the whole thing through to /dev/net/tun. It expects the exact * same format: what a coincidence! */ if (writev(net_info->tunfd, iov, out) < 0) warnx("Write to tun failed (%d)?", errno); /* * Done with that one; wait_for_vq_desc() will send the interrupt if * all packets are processed. */ add_used(vq, head, 0); }
/* * This handles packets coming in from the tun device to our Guest. Like all * service routines, it gets called again as soon as it returns, so you don't * see a while(1) loop here. */ static void net_input(struct virtqueue *vq) { int len; unsigned int head, out, in; struct iovec iov[vq->vring.num]; struct net_info *net_info = vq->dev->priv; /* * Get a descriptor to write an incoming packet into. This will also * send an interrupt if they're out of descriptors. */ head = wait_for_vq_desc(vq, iov, &out, &in); if (out) errx(1, "Output buffers in net input queue?"); /* * If it looks like we'll block reading from the tun device, send them * an interrupt. */ if (vq->pending_used && will_block(net_info->tunfd)) trigger_irq(vq); /* * Read in the packet. This is where we normally wait (when there's no * incoming network traffic). */ len = readv(net_info->tunfd, iov, in); if (len <= 0) warn("Failed to read from tun (%d).", errno); /* * Mark that packet buffer as used, but don't interrupt here. We want * to wait until we've done as much work as we can. */ add_used(vq, head, len); }
void *consin(void *arg) { struct virtio_threadarg *a = arg; char *line, *outline; static char consline[128]; static struct scatterlist iov[32]; static struct scatterlist out[] = { {NULL, sizeof(outline)}, }; static struct scatterlist in[] = { {NULL, sizeof(line)}, }; static unsigned int inlen, outlen, conslen; struct virtqueue *v = a->arg->virtio; fprintf(stderr, "consin thread ..\n"); uint16_t head, gaveit = 0, gotitback = 0; uint32_t vv; int i; int num; //char c[1]; if (debug) fprintf(stderr, "Spin on console being read, print num queues, halt\n"); for(num = 0;! quit;num++) { //int debug = 1; /* host: use any buffers we should have been sent. */ head = wait_for_vq_desc(v, iov, &outlen, &inlen); if (debug) fprintf(stderr, "vq desc head %d, gaveit %d gotitback %d\n", head, gaveit, gotitback); for(i = 0; debug && i < outlen + inlen; i++) fprintf(stderr, "v[%d/%d] v %p len %d\n", i, outlen + inlen, iov[i].v, iov[i].length); if (debug) fprintf(stderr, "outlen is %d; inlen is %d\n", outlen, inlen); /* host: fill in the writeable buffers. */ for (i = outlen; i < outlen + inlen; i++) { /* host: read a line. */ memset(consline, 0, 128); if (read(0, consline, 1) < 0) { exit(0); } if (debug) fprintf(stderr, "CONSIN: GOT A LINE:%s:\n", consline); if (debug) fprintf(stderr, "CONSIN: OUTLEN:%d:\n", outlen); if (strlen(consline) < 3 && consline[0] == 'q' ) { quit = 1; break; } memmove(iov[i].v, consline, strlen(consline)+ 1); iov[i].length = strlen(consline) + 1; } if (debug) fprintf(stderr, "call add_used\n"); /* host: now ack that we used them all. */ add_used(v, head, outlen+inlen); /* turn off consdata - the IRQ injection isn't right */ //consdata = 1; if (debug) fprintf(stderr, "DONE call add_used\n"); // Send spurious for testing (Gan) set_posted_interrupt(0xE5); virtio_mmio_set_vring_irq(); ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0); } fprintf(stderr, "All done\n"); return NULL; }