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>

+90
+90
Documentation/lguest/lguest.c
··· 41 41 #include "linux/virtio_net.h" 42 42 #include "linux/virtio_blk.h" 43 43 #include "linux/virtio_console.h" 44 + #include "linux/virtio_rng.h" 44 45 #include "linux/virtio_ring.h" 45 46 #include "asm-x86/bootparam.h" 46 47 /*L:110 We can ignore the 39 include files we need for this program, but I do ··· 199 198 #define le16_to_cpu(v16) (v16) 200 199 #define le32_to_cpu(v32) (v32) 201 200 #define le64_to_cpu(v64) (v64) 201 + 202 + /* Is this iovec empty? */ 203 + static bool iov_empty(const struct iovec iov[], unsigned int num_iov) 204 + { 205 + unsigned int i; 206 + 207 + for (i = 0; i < num_iov; i++) 208 + if (iov[i].iov_len) 209 + return false; 210 + return true; 211 + } 212 + 213 + /* Take len bytes from the front of this iovec. */ 214 + static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) 215 + { 216 + unsigned int i; 217 + 218 + for (i = 0; i < num_iov; i++) { 219 + unsigned int used; 220 + 221 + used = iov[i].iov_len < len ? iov[i].iov_len : len; 222 + iov[i].iov_base += used; 223 + iov[i].iov_len -= used; 224 + len -= used; 225 + } 226 + assert(len == 0); 227 + } 202 228 203 229 /* The device virtqueue descriptors are followed by feature bitmasks. */ 204 230 static u8 *get_feature_bits(struct device *dev) ··· 1706 1678 verbose("device %u: virtblock %llu sectors\n", 1707 1679 devices.device_num, le64_to_cpu(conf.capacity)); 1708 1680 } 1681 + 1682 + /* Our random number generator device reads from /dev/random into the Guest's 1683 + * input buffers. The usual case is that the Guest doesn't want random numbers 1684 + * and so has no buffers although /dev/random is still readable, whereas 1685 + * console is the reverse. 1686 + * 1687 + * The same logic applies, however. */ 1688 + static bool handle_rng_input(int fd, struct device *dev) 1689 + { 1690 + int len; 1691 + unsigned int head, in_num, out_num, totlen = 0; 1692 + struct iovec iov[dev->vq->vring.num]; 1693 + 1694 + /* First we need a buffer from the Guests's virtqueue. */ 1695 + head = get_vq_desc(dev->vq, iov, &out_num, &in_num); 1696 + 1697 + /* If they're not ready for input, stop listening to this file 1698 + * descriptor. We'll start again once they add an input buffer. */ 1699 + if (head == dev->vq->vring.num) 1700 + return false; 1701 + 1702 + if (out_num) 1703 + errx(1, "Output buffers in rng?"); 1704 + 1705 + /* This is why we convert to iovecs: the readv() call uses them, and so 1706 + * it reads straight into the Guest's buffer. We loop to make sure we 1707 + * fill it. */ 1708 + while (!iov_empty(iov, in_num)) { 1709 + len = readv(dev->fd, iov, in_num); 1710 + if (len <= 0) 1711 + err(1, "Read from /dev/random gave %i", len); 1712 + iov_consume(iov, in_num, len); 1713 + totlen += len; 1714 + } 1715 + 1716 + /* Tell the Guest about the new input. */ 1717 + add_used_and_trigger(fd, dev->vq, head, totlen); 1718 + 1719 + /* Everything went OK! */ 1720 + return true; 1721 + } 1722 + 1723 + /* And this creates a "hardware" random number device for the Guest. */ 1724 + static void setup_rng(void) 1725 + { 1726 + struct device *dev; 1727 + int fd; 1728 + 1729 + fd = open_or_die("/dev/random", O_RDONLY); 1730 + 1731 + /* The device responds to return from I/O thread. */ 1732 + dev = new_device("rng", VIRTIO_ID_RNG, fd, handle_rng_input); 1733 + 1734 + /* The device has one virtqueue, where the Guest places inbufs. */ 1735 + add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd); 1736 + 1737 + verbose("device %u: rng\n", devices.device_num++); 1738 + } 1709 1739 /* That's the end of device setup. */ 1710 1740 1711 1741 /*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */ ··· 1834 1748 { "verbose", 0, NULL, 'v' }, 1835 1749 { "tunnet", 1, NULL, 't' }, 1836 1750 { "block", 1, NULL, 'b' }, 1751 + { "rng", 0, NULL, 'r' }, 1837 1752 { "initrd", 1, NULL, 'i' }, 1838 1753 { NULL }, 1839 1754 }; ··· 1908 1821 break; 1909 1822 case 'b': 1910 1823 setup_block_file(optarg); 1824 + break; 1825 + case 'r': 1826 + setup_rng(); 1911 1827 break; 1912 1828 case 'i': 1913 1829 initrd_name = optarg;