1 /* Virtio helper functions from linux/tools/lguest/lguest.c
3 * Copyright (C) 1991-2016, the Linux Kernel authors
4 * Copyright (c) 2016 Google Inc.
7 * Rusty Russell <rusty@rustcorp.com.au>
8 * Michael Taufen <mtaufen@gmail.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * The code from lguest.c has been modified for Akaros.
22 * Original linux/tools/lguest/lguest.c:
23 * https://github.com/torvalds/linux/blob/v4.5/tools/lguest/lguest.c
24 * most recent hash on the file as of v4.5 tag:
25 * e523caa601f4a7c2fa1ecd040db921baf7453798
30 #include <sys/eventfd.h>
32 #include <vmm/virtio.h>
33 #include <vmm/virtio_mmio.h>
35 void *cons_receiveq_fn(void *_vq) // host -> guest
37 struct virtio_vq *vq = _vq;
47 " Virtio device: (not sure which one): Error, device behavior.\n"
48 " The device must provide a valid virtio_vq as an argument to %s."
49 , __FILE__, __LINE__, __func__);
51 // NOTE: The virtio_next_avail_vq_desc will not write more than
52 // vq->vring.num entries to iov, and the device implementation
53 // (virtio_mmio.c) will not allow the driver to set vq->vring.num to a
54 // value greater than QueueNumMax (vq->qnum_max), so you are safe as
55 // long as your iov is at least vq->qnum_max iovecs in size.
56 iov = malloc(vq->qnum_max * sizeof(struct iovec));
58 if (vq->qready == 0x0)
59 VIRTIO_DEV_ERRX(vq->vqdev,
60 "The service function for queue '%s' was launched before the driver set QueueReady to 0x1."
63 // NOTE: This will block in 2 places:
64 // - reading from stdin
65 // - reading from eventfd in virtio_next_avail_vq_desc
67 head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen);
70 // virtio-v1.0-cs04 s5.3.6.1 Device Operation (console section)
71 VIRTIO_DRI_ERRX(vq->vqdev,
72 "The driver placed a device-readable buffer in the console device's receiveq.\n"
73 " See virtio-v1.0-cs04 s5.3.6.1 Device Operation");
76 // TODO: We may want to add some sort of console abort
77 // (e.g. type q and enter to quit)
78 // readv from stdin as much as we can (to end of bufs or end of input)
79 num_read = readv(0, iov, ilen);
81 VIRTIO_DEV_ERRX(vq->vqdev,
82 "Encountered an error trying to read input from stdin (fd 0).");
84 // You pass the number of bytes written to virtio_add_used_desc
85 virtio_add_used_desc(vq, head, num_read);
87 // Poke the guest however the mmio transport prefers
88 // NOTE: assuming that the mmio transport was used for now
89 virtio_mmio_set_vring_irq(vq->vqdev->transport_dev);
90 if (((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest)
91 ((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest();
93 VIRTIO_DEV_ERRX(vq->vqdev,
94 "The host MUST provide a way for device interrupts to be sent to the guest. The 'poke_guest' function pointer on the vq->vqdev->transport_dev (assumed to be a struct virtio_mmio_dev) was not set.");
100 void *cons_transmitq_fn(void *_vq) // guest -> host
102 struct virtio_vq *vq = _vq;
111 " Virtio device: (not sure which one): Error, device behavior.\n"
112 " The device must provide a valid virtio_vq as an argument to %s."
113 , __FILE__, __LINE__, __func__);
115 // NOTE: The virtio_next_avail_vq_desc will not write more than
116 // vq->vring.num entries to iov, and the device implementation
117 // (virtio_mmio.c) will not allow the driver to set vq->vring.num to a
118 // value greater than QueueNumMax (vq->qnum_max), so you are safe as
119 // long as your iov is at least vq->qnum_max iovecs in size.
120 iov = malloc(vq->qnum_max * sizeof(struct iovec));
122 if (vq->qready == 0x0)
123 VIRTIO_DEV_ERRX(vq->vqdev,
124 "The service function for queue '%s' was launched before the driver set QueueReady to 0x1."
129 head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen);
132 // virtio-v1.0-cs04 s5.3.6.1 Device Operation (console section)
133 VIRTIO_DRI_ERRX(vq->vqdev,
134 "The driver placed a device-writeable buffer in the console device's transmitq.\n"
135 " See virtio-v1.0-cs04 s5.3.6.1 Device Operation");
137 // Process the buffers:
138 for (i = 0; i < olen; ++i) {
139 for (j = 0; j < iov[i].iov_len; ++j)
140 printf("%c", ((char *)iov[i].iov_base)[j]);
144 // Add all the buffers to the used ring.
145 // Pass 0 because we wrote nothing.
146 virtio_add_used_desc(vq, head, 0);
148 // Poke the guest however the mmio transport prefers
149 // NOTE: assuming that the mmio transport was used for now
150 virtio_mmio_set_vring_irq(vq->vqdev->transport_dev);
151 if (((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest)
152 ((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest();
154 VIRTIO_DEV_ERRX(vq->vqdev,
155 "The host MUST provide a way for device interrupts to be sent to the guest. The 'poke_guest' function pointer on the vq->vqdev->transport_dev (assumed to be a struct virtio_mmio_dev) was not set.");