diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2008-07-29 10:58:33 -0400 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-07-28 19:58:34 -0400 |
| commit | 28fd6d7f953711fbf67496701be05513052d967d (patch) | |
| tree | 08b3b76e4b0e3440a552facbbef55993be2932e1 | |
| parent | dec6a2be085f046d42eb0bdce95ecb73de526429 (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>
| -rw-r--r-- | Documentation/lguest/lguest.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 684d61191bee..a1fca9db788e 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? */ | ||
| 204 | static 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. */ | ||
| 215 | static 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. */ |
| 203 | static u8 *get_feature_bits(struct device *dev) | 231 | static 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. */ | ||
| 1716 | static 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. */ | ||
| 1752 | static 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; |
