Hi,
qemu 1.3 has added a virtio entropy device. Here is a driver for it.
Comments? OKs?
As the entropy reserve of the host may not be unlimited, the OpenBSD guest
should only ask for entropy when it actually needs it. Would it make sense
to add an API that allows a driver to determine how full the entropy queue
is? This could also be used by some hardware drivers to avoid polling for
entropy if not necessary. E.g. amdpm does the polling in every timer tick,
which is wasteful.
Cheers,
Stefan
diff --git share/man/man4/Makefile share/man/man4/Makefile
index ab6d258..3e36766 100644
--- share/man/man4/Makefile
+++ share/man/man4/Makefile
@@ -66,9 +66,9 @@ MAN= aac.4 ac97.4 acphy.4 \
uthum.4 uticom.4 utwitch.4 utrh.4 uts.4 uvideo.4 uvisor.4 uvscom.4 \
uyap.4 \
vether.4 vga.4 vgafb.4 vge.4 \
- viapm.4 viasio.4 vic.4 video.4 vio.4 vioblk.4 viomb.4 virtio.4 vlan.4 \
- vmt.4 vnd.4 vr.4 \
- vscsi.4 vte.4 \
+ viapm.4 viasio.4 vic.4 video.4 \
+ vio.4 vioblk.4 viomb.4 viornd.4 virtio.4 \
+ vlan.4 vmt.4 vnd.4 vr.4 vscsi.4 vte.4 \
watchdog.4 wb.4 wbenv.4 wbng.4 wbsd.4 wbsio.4 wd.4 wdc.4 we.4 \
wi.4 wpi.4 wscons.4 wsdisplay.4 wskbd.4 wsmouse.4 wsmux.4 \
xe.4 xf86.4 xge.4 xl.4 xmphy.4 yds.4 ym.4 zero.4 zyd.4
diff --git share/man/man4/viornd.4 share/man/man4/viornd.4
new file mode 100644
index 0000000..09ff465
--- /dev/null
+++ share/man/man4/viornd.4
@@ -0,0 +1,45 @@
+.\" $OpenBSD: $
+.\"
+.\" Copyright (c) 2013 Stefan Fritsch <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: January 25 2013 $
+.Dt VIORND 4
+.Os
+.Sh NAME
+.Nm viornd
+.Nd VirtIO random number device
+.Sh SYNOPSIS
+.Cd "viornd* at virtio?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides a virtual random number generator using a
+.Xr virtio 4
+entropy device provided by QEMU 1.3 and later, and possibly by other
+hypervisors.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr virtio 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Stefan Fritsch Aq [email protected] .
diff --git share/man/man4/virtio.4 share/man/man4/virtio.4
index 16ad4ba..33ce729 100644
--- share/man/man4/virtio.4
+++ share/man/man4/virtio.4
@@ -40,6 +40,8 @@ VirtIO network device
VirtIO disk
.It Xr viomb 4
VirtIO memory ballooning driver
+.It Xr viornd 4
+VirtIO random number device
.El
.Sh SEE ALSO
.Xr intro 4
diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
index ca0a4b2..8f41464 100644
--- sys/arch/amd64/conf/GENERIC
+++ sys/arch/amd64/conf/GENERIC
@@ -612,3 +612,4 @@ virtio* at pci? # Virtio PCI device
vioblk* at virtio? # Virtio block device
vio* at virtio? # Virtio network device
viomb* at virtio? # Virtio memory ballooning device
+viornd* at virtio? # Virtio entropy device
diff --git sys/arch/i386/conf/GENERIC sys/arch/i386/conf/GENERIC
index 190677e..9c0417d 100644
--- sys/arch/i386/conf/GENERIC
+++ sys/arch/i386/conf/GENERIC
@@ -802,3 +802,4 @@ virtio* at pci? # Virtio PCI device
vioblk* at virtio? # Virtio block device
vio* at virtio? # Virtio network device
viomb* at virtio? # Virtio memory ballooning device
+viornd* at virtio? # Virtio entropy device
diff --git sys/dev/pci/files.pci sys/dev/pci/files.pci
index aebacb8..3155a7f 100644
--- sys/dev/pci/files.pci
+++ sys/dev/pci/files.pci
@@ -844,3 +844,7 @@ file dev/pci/vioblk.c vioblk
device viomb
attach viomb at virtio
file dev/pci/viomb.c viomb
+
+device viornd
+attach viornd at virtio
+file dev/pci/viornd.c viornd
diff --git sys/dev/pci/viornd.c sys/dev/pci/viornd.c
new file mode 100644
index 0000000..3669df3
--- /dev/null
+++ sys/dev/pci/viornd.c
@@ -0,0 +1,168 @@
+/* $OpenBSD: $ */
+
+/*
+ * Copyright (c) 2013 Stefan Fritsch <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/timeout.h>
+#include <machine/bus.h>
+#include <sys/device.h>
+#include <dev/rndvar.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/virtioreg.h>
+#include <dev/pci/virtiovar.h>
+
+/*
+ * The host may not have an unlimited supply of entropy. Therefore, we must
+ * not blindly get as much entropy as we can. Instead, we just request
+ * VIORND_BUFSIZE bytes at boot and every VIORND_INTERVAL seconds.
+ * XXX There should be an API to check if we actually need more entropy.
+ */
+#define VIORND_BUFSIZE 16
+#define VIORND_INTERVAL 300
+
+struct viornd_softc {
+ struct device sc_dev;
+ struct virtio_softc *sc_virtio;
+
+ struct virtqueue sc_vq;
+ int sc_buf[VIORND_BUFSIZE/sizeof(int)];
+ bus_dmamap_t sc_dmamap;
+
+ struct timeout sc_tick;
+};
+
+int viornd_match(struct device *, void *, void *);
+void viornd_attach(struct device *, struct device *, void *);
+int viornd_vq_done(struct virtqueue *);
+void viornd_tick(void *);
+
+struct cfattach viornd_ca = {
+ sizeof(struct viornd_softc),
+ viornd_match,
+ viornd_attach,
+ NULL
+};
+
+struct cfdriver viornd_cd = {
+ NULL, "viornd", DV_DULL
+};
+
+
+int viornd_match(struct device *parent, void *match, void *aux)
+{
+ struct virtio_softc *va = aux;
+ if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_ENTROPY)
+ return 1;
+ return 0;
+}
+
+void
+viornd_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct viornd_softc *sc = (struct viornd_softc *)self;
+ struct virtio_softc *vsc = (struct virtio_softc *)parent;
+
+ vsc->sc_vqs = &sc->sc_vq;
+ vsc->sc_nvqs = 1;
+ vsc->sc_config_change = 0;
+ if (vsc->sc_child)
+ panic("already attached to something else");
+ vsc->sc_child = self;
+ vsc->sc_ipl = IPL_NET;
+ vsc->sc_intrhand = virtio_vq_intr;
+ sc->sc_virtio = vsc;
+
+ virtio_negotiate_features(vsc, 0, NULL);
+
+ if (bus_dmamap_create(sc->sc_virtio->sc_dmat, VIORND_BUFSIZE, 1,
+ VIORND_BUFSIZE, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
+ &sc->sc_dmamap)) {
+ printf("\nCan't alloc dmamap\n");
+ goto err;
+ }
+ if (bus_dmamap_load(sc->sc_virtio->sc_dmat, sc->sc_dmamap,
+ sc->sc_buf, VIORND_BUFSIZE, NULL, BUS_DMA_NOWAIT|BUS_DMA_READ)) {
+ printf("\nCan't load dmamap\n");
+ goto err2;
+ }
+
+ if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, VIORND_BUFSIZE, 1,
+ "Entropy request") != 0) {
+ printf("\nCan't alloc virtqueue\n");
+ goto err2;
+ }
+
+ sc->sc_vq.vq_done = viornd_vq_done;
+ virtio_start_vq_intr(vsc, &sc->sc_vq);
+ timeout_set(&sc->sc_tick, viornd_tick, sc);
+ timeout_add(&sc->sc_tick, 1);
+
+ printf("\n");
+ return;
+err2:
+ bus_dmamap_destroy(vsc->sc_dmat, sc->sc_dmamap);
+err:
+ vsc->sc_child = VIRTIO_CHILD_ERROR;
+ return;
+}
+
+int
+viornd_vq_done(struct virtqueue *vq)
+{
+ struct virtio_softc *vsc = vq->vq_owner;
+ struct viornd_softc *sc = (struct viornd_softc *)vsc->sc_child;
+ int slot, len, i;
+
+ if (virtio_dequeue(vsc, vq, &slot, &len) != 0)
+ return 0;
+ bus_dmamap_sync(vsc->sc_dmat, sc->sc_dmamap, 0, VIORND_BUFSIZE,
+ BUS_DMASYNC_POSTREAD);
+ if (len > VIORND_BUFSIZE) {
+ printf("%s inconsistent descriptor length %d > %d\n",
+ sc->sc_dev.dv_xname, len, VIORND_BUFSIZE);
+ goto out;
+ }
+
+ for (i = 0; (i + 1) * sizeof(int) <= len; i++)
+ add_true_randomness(sc->sc_buf[i]);
+
+ timeout_add_sec(&sc->sc_tick, VIORND_INTERVAL);
+
+out:
+ virtio_dequeue_commit(vq, slot);
+ return 1;
+}
+
+void
+viornd_tick(void *arg)
+{
+ struct viornd_softc *sc = arg;
+ struct virtio_softc *vsc = sc->sc_virtio;
+ struct virtqueue *vq = &sc->sc_vq;
+ int slot;
+
+ bus_dmamap_sync(vsc->sc_dmat, sc->sc_dmamap, 0, VIORND_BUFSIZE,
+ BUS_DMASYNC_PREREAD);
+ if (virtio_enqueue_prep(vq, &slot) != 0 ||
+ virtio_enqueue_reserve(vq, slot, 1) != 0) {
+ panic("%s virtqueue enqueue failed", sc->sc_dev.dv_xname);
+ }
+ virtio_enqueue(vq, slot, sc->sc_dmamap, 0);
+ virtio_enqueue_commit(vsc, vq, slot, 1);
+}