aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-07-29 10:58:33 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-07-28 19:58:34 -0400
commit28fd6d7f953711fbf67496701be05513052d967d (patch)
tree08b3b76e4b0e3440a552facbbef55993be2932e1 /Documentation
parentdec6a2be085f046d42eb0bdce95ecb73de526429 (diff)
lguest: virtio-rng support
This is a simple patch to add support for the virtio "hardware random generator" to lguest. It gets about 1.2 MB/sec reading from /dev/hwrng in the guest. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'Documentation')
-rw-r--r--Documentation/lguest/lguest.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 684d61191be..a1fca9db788 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -41,6 +41,7 @@
41#include "linux/virtio_net.h" 41#include "linux/virtio_net.h"
42#include "linux/virtio_blk.h" 42#include "linux/virtio_blk.h"
43#include "linux/virtio_console.h" 43#include "linux/virtio_console.h"
44#include "linux/virtio_rng.h"
44#include "linux/virtio_ring.h" 45#include "linux/virtio_ring.h"
45#include "asm-x86/bootparam.h" 46#include "asm-x86/bootparam.h"
46/*L:110 We can ignore the 39 include files we need for this program, but I do 47/*L:110 We can ignore the 39 include files we need for this program, but I do
@@ -199,6 +200,33 @@ static void *_convert(struct iovec *iov, size_t size, size_t align,
199#define le32_to_cpu(v32) (v32) 200#define le32_to_cpu(v32) (v32)
200#define le64_to_cpu(v64) (v64) 201#define le64_to_cpu(v64) (v64)
201 202
203/* Is this iovec empty? */
204static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
205{
206 unsigned int i;
207
208 for (i = 0; i < num_iov; i++)
209 if (iov[i].iov_len)
210 return false;
211 return true;
212}
213
214/* Take len bytes from the front of this iovec. */
215static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
216{
217 unsigned int i;
218
219 for (i = 0; i < num_iov; i++) {
220 unsigned int used;
221
222 used = iov[i].iov_len < len ? iov[i].iov_len : len;
223 iov[i].iov_base += used;
224 iov[i].iov_len -= used;
225 len -= used;
226 }
227 assert(len == 0);
228}
229
202/* The device virtqueue descriptors are followed by feature bitmasks. */ 230/* The device virtqueue descriptors are followed by feature bitmasks. */
203static u8 *get_feature_bits(struct device *dev) 231static u8 *get_feature_bits(struct device *dev)
204{ 232{
@@ -1678,6 +1706,64 @@ static void setup_block_file(const char *filename)
1678 verbose("device %u: virtblock %llu sectors\n", 1706 verbose("device %u: virtblock %llu sectors\n",
1679 devices.device_num, le64_to_cpu(conf.capacity)); 1707 devices.device_num, le64_to_cpu(conf.capacity));
1680} 1708}
1709
1710/* Our random number generator device reads from /dev/random into the Guest's
1711 * input buffers. The usual case is that the Guest doesn't want random numbers
1712 * and so has no buffers although /dev/random is still readable, whereas
1713 * console is the reverse.
1714 *
1715 * The same logic applies, however. */
1716static bool handle_rng_input(int fd, struct device *dev)
1717{
1718 int len;
1719 unsigned int head, in_num, out_num, totlen = 0;
1720 struct iovec iov[dev->vq->vring.num];
1721
1722 /* First we need a buffer from the Guests's virtqueue. */
1723 head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
1724
1725 /* If they're not ready for input, stop listening to this file
1726 * descriptor. We'll start again once they add an input buffer. */
1727 if (head == dev->vq->vring.num)
1728 return false;
1729
1730 if (out_num)
1731 errx(1, "Output buffers in rng?");
1732
1733 /* This is why we convert to iovecs: the readv() call uses them, and so
1734 * it reads straight into the Guest's buffer. We loop to make sure we
1735 * fill it. */
1736 while (!iov_empty(iov, in_num)) {
1737 len = readv(dev->fd, iov, in_num);
1738 if (len <= 0)
1739 err(1, "Read from /dev/random gave %i", len);
1740 iov_consume(iov, in_num, len);
1741 totlen += len;
1742 }
1743
1744 /* Tell the Guest about the new input. */
1745 add_used_and_trigger(fd, dev->vq, head, totlen);
1746
1747 /* Everything went OK! */
1748 return true;
1749}
1750
1751/* And this creates a "hardware" random number device for the Guest. */
1752static void setup_rng(void)
1753{
1754 struct device *dev;
1755 int fd;
1756
1757 fd = open_or_die("/dev/random", O_RDONLY);
1758
1759 /* The device responds to return from I/O thread. */
1760 dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input);
1761
1762 /* The device has one virtqueue, where the Guest places inbufs. */
1763 add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
1764
1765 verbose("device %u: rng\n", devices.device_num++);
1766}
1681/* That's the end of device setup. */ 1767/* That's the end of device setup. */
1682 1768
1683/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ 1769/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
@@ -1748,6 +1834,7 @@ static struct option opts[] = {
1748 { "verbose", 0, NULL, 'v' }, 1834 { "verbose", 0, NULL, 'v' },
1749 { "tunnet", 1, NULL, 't' }, 1835 { "tunnet", 1, NULL, 't' },
1750 { "block", 1, NULL, 'b' }, 1836 { "block", 1, NULL, 'b' },
1837 { "rng", 0, NULL, 'r' },
1751 { "initrd", 1, NULL, 'i' }, 1838 { "initrd", 1, NULL, 'i' },
1752 { NULL }, 1839 { NULL },
1753}; 1840};
@@ -1822,6 +1909,9 @@ int main(int argc, char *argv[])
1822 case 'b': 1909 case 'b':
1823 setup_block_file(optarg); 1910 setup_block_file(optarg);
1824 break; 1911 break;
1912 case 'r':
1913 setup_rng();
1914 break;
1825 case 'i': 1915 case 'i':
1826 initrd_name = optarg; 1916 initrd_name = optarg;
1827 break; 1917 break;