[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 1/1] virtio-rng: device to send host entropy to gues
From: |
Amit Shah |
Subject: |
[Qemu-devel] [PATCH 1/1] virtio-rng: device to send host entropy to guest |
Date: |
Wed, 16 May 2012 17:00:28 +0530 |
The Linux kernel already has a virtio-rng driver, this is the device
implementation.
When Linux needs more entropy, it puts a buffer in the vq. We then put
entropy into that buffer, and push it back to the guest.
Feeding randomness from host's /dev/urandom into the guest is
sufficient, so this is a simple implementation that opens /dev/urandom
and reads from it whenever required.
Invocation is simple:
qemu ... -device virtio-rng-pci
In the guest, we see
$ cat /sys/devices/virtual/misc/hw_random/rng_available
virtio
$ cat /sys/devices/virtual/misc/hw_random/rng_current
virtio
There are ways to extend the device to be more generic and collect
entropy from other sources, but this is simple enough and works for now.
Signed-off-by: Amit Shah <address@hidden>
---
Makefile.objs | 1 +
hw/pci.h | 1 +
hw/virtio-pci.c | 50 +++++++++++++++++++++
hw/virtio-rng.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/virtio-rng.h | 18 ++++++++
hw/virtio.h | 2 +
6 files changed, 202 insertions(+), 0 deletions(-)
create mode 100644 hw/virtio-rng.c
create mode 100644 hw/virtio-rng.h
diff --git a/Makefile.objs b/Makefile.objs
index 70c5c79..5850762 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -210,6 +210,7 @@ user-obj-y += $(qom-obj-twice-y)
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
+hw-obj-$(CONFIG_VIRTIO) += virtio-rng.o
hw-obj-y += usb/libhw.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
diff --git a/hw/pci.h b/hw/pci.h
index 8d0aa49..0a22f91 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -76,6 +76,7 @@
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004
+#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define FMT_PCIBUS PRIx64
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 4a4413d..7f2d630 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -812,6 +812,28 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
return virtio_exit_pci(pci_dev);
}
+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);
+ if (!vdev) {
+ return -1;
+ }
+ virtio_init_pci(proxy, vdev);
+ return 0;
+}
+
+static int virtio_rng_exit_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ virtio_pci_stop_ioeventfd(proxy);
+ virtio_rng_exit(proxy->vdev);
+ return virtio_exit_pci(pci_dev);
+}
+
static Property virtio_blk_properties[] = {
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
@@ -937,6 +959,33 @@ static TypeInfo virtio_balloon_info = {
.class_init = virtio_balloon_class_init,
};
+static Property virtio_rng_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_rng_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_rng_init_pci;
+ k->exit = virtio_rng_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_rng_properties;
+}
+
+static TypeInfo virtio_rng_info = {
+ .name = "virtio-rng-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_rng_class_init,
+};
+
static int virtio_scsi_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
@@ -998,6 +1047,7 @@ static void virtio_pci_register_types(void)
type_register_static(&virtio_serial_info);
type_register_static(&virtio_balloon_info);
type_register_static(&virtio_scsi_info);
+ type_register_static(&virtio_rng_info);
}
type_init(virtio_pci_register_types)
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
new file mode 100644
index 0000000..e1f3d1c
--- /dev/null
+++ b/hw/virtio-rng.c
@@ -0,0 +1,130 @@
+/* A virtio device for feeding entropy into a guest.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ * Copyright 2012 Amit Shah <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "iov.h"
+#include "qdev.h"
+#include "virtio.h"
+#include "virtio-rng.h"
+
+typedef struct VirtIORNG {
+ VirtIODevice vdev;
+
+ DeviceState *qdev;
+
+ /* Only one vq - guest puts a buffer on it when it needs entropy */
+ VirtQueue *vq;
+
+ int input_fd;
+} VirtIORNG;
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+ VirtQueueElement elem;
+ char *buf;
+ ssize_t size, offset, ret;
+
+ if (!virtqueue_pop(vq, &elem)) {
+ return;
+ }
+ size = iov_size(elem.in_sg, elem.in_num);
+
+ buf = g_malloc(size);
+ do {
+ ret = read(vrng->input_fd, buf, size);
+ } while (ret == -1 && errno == EINTR);
+ if (ret < 0) {
+ /* We can't get randomness -- give up for now. */
+ virtqueue_push(vq, &elem, 0);
+ goto skip;
+ }
+
+ offset = 0;
+ size = ret;
+ while (offset < size) {
+ size_t len;
+
+ /* We've already popped the first elem */
+ if (offset && !virtqueue_pop(vq, &elem)) {
+ break;
+ }
+
+ len = iov_from_buf(elem.in_sg, elem.in_num,
+ buf + offset, 0, size - offset);
+ offset += len;
+
+ virtqueue_push(vq, &elem, len);
+ }
+skip:
+ g_free(buf);
+ virtio_notify(vdev, vq);
+}
+
+static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
+{
+ return f;
+}
+
+static void virtio_rng_save(QEMUFile *f, void *opaque)
+{
+ VirtIORNG *vrng = opaque;
+
+ virtio_save(&vrng->vdev, f);
+}
+
+static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VirtIORNG *vrng = opaque;
+
+ if (version_id != 1) {
+ return -EINVAL;
+ }
+ virtio_load(&vrng->vdev, f);
+
+ return 0;
+}
+
+VirtIODevice *virtio_rng_init(DeviceState *dev)
+{
+ VirtIORNG *vrng;
+ VirtIODevice *vdev;
+ int input_fd;
+
+ input_fd = open("/dev/urandom", O_RDONLY);
+ if (input_fd < 0) {
+ error_report("error %d opening /dev/urandom", errno);
+ return NULL;
+ }
+
+ vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
+ sizeof(VirtIORNG));
+
+ vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+ vrng->input_fd = input_fd;
+
+ vrng->vq = virtio_add_queue(vdev, 8, handle_input);
+ vrng->vdev.get_features = get_features;
+
+ vrng->qdev = dev;
+ register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
+ virtio_rng_load, vrng);
+
+ return vdev;
+}
+
+void virtio_rng_exit(VirtIODevice *vdev)
+{
+ VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+ close(vrng->input_fd);
+ unregister_savevm(vrng->qdev, "virtio-rng", vrng);
+ virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
new file mode 100644
index 0000000..2e1eba3
--- /dev/null
+++ b/hw/virtio-rng.h
@@ -0,0 +1,18 @@
+/*
+ * Virtio RNG Support
+ *
+ * Copyright Red Hat, Inc. 2012
+ * Copyright Amit Shah <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef _QEMU_VIRTIO_RNG_H
+#define _QEMU_VIRTIO_RNG_H
+
+/* The Virtio ID for the virtio rng device */
+#define VIRTIO_ID_RNG 4
+
+#endif
diff --git a/hw/virtio.h b/hw/virtio.h
index 0aef7d1..0315e0c 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -201,6 +201,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev,
virtio_serial_conf *serial);
VirtIODevice *virtio_balloon_init(DeviceState *dev);
typedef struct VirtIOSCSIConf VirtIOSCSIConf;
VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
+VirtIODevice *virtio_rng_init(DeviceState *dev);
#ifdef CONFIG_LINUX
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
#endif
@@ -211,6 +212,7 @@ void virtio_blk_exit(VirtIODevice *vdev);
void virtio_serial_exit(VirtIODevice *vdev);
void virtio_balloon_exit(VirtIODevice *vdev);
void virtio_scsi_exit(VirtIODevice *vdev);
+void virtio_rng_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
--
1.7.7.6