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 /Documentation | |
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>
Diffstat (limited to 'Documentation')
-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; |