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);
+}

Reply via email to