On 02/01/2010 07:34 AM, Ian Molton wrote:
This patch adds support for virtio-rng. Data is read from a chardev and
can be either raw entropy or received via the EGD protocol.
Signed-off-by: Ian Molton<ian.mol...@collabora.co.uk>
---
Makefile.target | 2 +-
hw/pci.h | 1 +
hw/virtio-pci.c | 27 +++++++
hw/virtio-rng.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/virtio-rng.h | 19 +++++
hw/virtio.h | 2 +
rng.h | 18 +++++
7 files changed, 270 insertions(+), 1 deletions(-)
create mode 100644 hw/virtio-rng.c
create mode 100644 hw/virtio-rng.h
create mode 100644 rng.h
diff --git a/Makefile.target b/Makefile.target
index 5c0ef1f..21d28f4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -172,7 +172,7 @@ ifdef CONFIG_SOFTMMU
obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o
gdbstub.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o
virtio-serial-bus.o
+obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o
virtio-serial-bus.o virtio-rng.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
diff --git a/hw/pci.h b/hw/pci.h
index 8b511d2..77cb543 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -69,6 +69,7 @@
#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
+#define PCI_DEVICE_ID_VIRTIO_RNG 0x1004
typedef uint64_t pcibus_t;
#define FMT_PCIBUS PRIx64
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 709d13e..f057388 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -22,6 +22,7 @@
#include "sysemu.h"
#include "msix.h"
#include "net.h"
+#include "rng.h"
#include "loader.h"
/* from Linux's linux/virtio_pci.h */
@@ -94,6 +95,7 @@ typedef struct {
uint32_t nvectors;
DriveInfo *dinfo;
NICConf nic;
+ RNGConf rng;
uint32_t host_features;
/* Max. number of ports we can have for a the virtio-serial device */
uint32_t max_virtserial_ports;
@@ -550,6 +552,21 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
return 0;
}
+static int virtio_rng_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_rng_init(&pci_dev->qdev,&proxy->rng);
+ virtio_init_pci(proxy, vdev,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ PCI_DEVICE_ID_VIRTIO_RNG,
Gerd (or the right person at Red Hat) needs to Ack the assignment of
this PCI device id.
+ PCI_CLASS_OTHERS,
+ 0x00);
+
+ return 0;
+}
+
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -603,6 +620,16 @@ static PCIDeviceInfo virtio_info[] = {
},
.qdev.reset = virtio_pci_reset,
},{
+ .qdev.name = "virtio-rng-pci",
+ .qdev.size = sizeof(VirtIOPCIProxy),
+ .init = virtio_rng_init_pci,
+ .exit = virtio_exit_pci,
+ .qdev.props = (Property[]) {
+ DEFINE_RNG_PROPERTIES(VirtIOPCIProxy, rng),
I don't see any reason to use a define here.
+ DEFINE_PROP_END_OF_LIST(),
+ },
+ .qdev.reset = virtio_pci_reset,
+ },{
/* end of list */
}
};
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
new file mode 100644
index 0000000..d8cbb74
--- /dev/null
+++ b/hw/virtio-rng.c
@@ -0,0 +1,202 @@
+/*
+ * Virtio RNG Device
+ *
+ * Copyright Collabora 2009
+ *
+ * Authors:
+ * Ian Molton<ian.mol...@collabora.co.uk>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "virtio.h"
+#include "virtio-rng.h"
+#include "rng.h"
+#include<sys/time.h>
+
+typedef struct VirtIORng
+{
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ CharDriverState *chr;
+ struct timeval last;
+ int rate;
+ int egd;
+ int entropy_remaining;
+ int pool;
+} VirtIORng;
+
+/* Maximum size of the buffer the guest expects */
+#define BUFF_MAX 64
+
+/* EGD protocol - we only use this command */
+#define EGD_READ_BLOCK 0x2
+
+#define EGD_MAX_BLOCK_SIZE 255
+#define EGD_MAX_REQUESTS 3
+#define EGD_MAX_POOL_SIZE (EGD_MAX_BLOCK_SIZE * (EGD_MAX_REQUESTS-1))
+
+static inline void req_entropy(VirtIORng *s) {
Coding style is off here (newline between ) and { ).
+ static const unsigned char entropy_rq[2] = { EGD_READ_BLOCK,
+ EGD_MAX_BLOCK_SIZE };
+ if (s->egd) {
+ /* Let the socket buffer up the incoming data for us. Max block size
+ for EGD protocol is (stupidly) 255, so make sure we always have a
+ block pending for performance. We can have 3 outstanding buffers */
+ if (s->pool<= EGD_MAX_POOL_SIZE) {
+ s->chr->chr_write(s->chr, entropy_rq, sizeof(entropy_rq));
+ s->pool += EGD_MAX_BLOCK_SIZE;
+ }
+ } else {
+ s->pool = BUFF_MAX;
+ }
+}
+
+static int vrng_can_read(void *opaque)
+{
+ VirtIORng *s = (VirtIORng *) opaque;
+ struct timeval now, d;
+ int max_entropy;
+
+ if (!virtio_queue_ready(s->vq) ||
+ !(s->vdev.status& VIRTIO_CONFIG_S_DRIVER_OK) ||
+ virtio_queue_empty(s->vq))
+ return 0;
+
+ req_entropy(s);
+
+ if (s->rate) {
+ gettimeofday(&now, NULL);
+ timersub(&now,&s->last,&d);
Can't call gettimeofday directly. You have to use qemu_gettimeofday().
But it would be better to not rely on gettimeofday and instead make use
of the rt_clock.
+static void virtio_rng_save(QEMUFile *f, void *opaque)
+{
+ VirtIORng *s = opaque;
+
+ virtio_save(&s->vdev, f);
+}
+
+static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VirtIORng *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ virtio_load(&s->vdev, f);
+ return 0;
+}
This doesn't look correct to me. There is absolutely no state
maintained by the virtio-rng backend? I find that hard to believe.
Regards,
Anthony Liguori