summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Fritsch <sf@cvs.openbsd.org>2014-01-21 21:14:59 +0000
committerStefan Fritsch <sf@cvs.openbsd.org>2014-01-21 21:14:59 +0000
commit7f21a9bf7d9ba818a2d0d26b4379d9ea3651461e (patch)
tree23e401f210dfd464f3f7055cd51274f929e6cd73
parent3645fc96e6ddec43a437816e218d61942eb65843 (diff)
Add virtio random driver
OK mikeb@ "seems fine" matthew@
-rw-r--r--share/man/man4/Makefile4
-rw-r--r--share/man/man4/viornd.460
-rw-r--r--share/man/man4/virtio.46
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/dev/pci/files.pci6
-rw-r--r--sys/dev/pci/viornd.c203
7 files changed, 278 insertions, 7 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index b5fa85c8c73..a324943a699 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.564 2013/12/20 22:10:19 matthew Exp $
+# $OpenBSD: Makefile,v 1.565 2014/01/21 21:14:58 sf Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
@@ -67,7 +67,7 @@ MAN= aac.4 ac97.4 acphy.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 vioscsi.4 virtio.4 vlan.4 \
+ vioblk.4 viomb.4 viornd.4 vioscsi.4 virtio.4 vlan.4 \
vmt.4 vmwpvs.4 vmx.4 vnd.4 vr.4 \
vscsi.4 vte.4 vxlan.4 \
watchdog.4 wb.4 wbenv.4 wbng.4 wbsd.4 wbsio.4 wd.4 wdc.4 wdsc.4 we.4 \
diff --git a/share/man/man4/viornd.4 b/share/man/man4/viornd.4
new file mode 100644
index 00000000000..9b8436461ea
--- /dev/null
+++ b/share/man/man4/viornd.4
@@ -0,0 +1,60 @@
+.\" $OpenBSD: viornd.4,v 1.1 2014/01/21 21:14:58 sf Exp $
+.\"
+.\" Copyright (c) 2014 Stefan Fritsch <sf@sfritsch.de>
+.\"
+.\" 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 21 2014 $
+.Dt VIORND 4
+.Os
+.Sh NAME
+.Nm viornd
+.Nd VirtIO random number device
+.Sh SYNOPSIS
+.Cd "viornd* at virtio? flags 0x00"
+.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.
+.Pp
+As there is currently no way for
+.Nm
+to determine how much entropy is needed, the second byte of the flags value
+can be used to configure how often it should request more entropy from the
+host.
+If the second lowest byte of the flags has a value from 1 to 15,
+.Nm
+will ask for 16 bytes of entropy every 15 * (1 << value) seconds.
+For example, flags == 0x100 means an interval of 30 seconds,
+0x500 means 8 minutes, 0xa00 means 256 minutes, and 0xf00 means about 6 days.
+For flags == 0, a default value will be used (currently 8 minutes).
+If the bit 0x1000 is set in the flags,
+.Nm
+will only request entropy from the host once during system boot.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr virtio 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 5.5 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Stefan Fritsch Aq sf@sfritsch.de .
diff --git a/share/man/man4/virtio.4 b/share/man/man4/virtio.4
index 2fe24232492..129b301c288 100644
--- a/share/man/man4/virtio.4
+++ b/share/man/man4/virtio.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: virtio.4,v 1.8 2013/12/20 22:10:19 matthew Exp $
+.\" $OpenBSD: virtio.4,v 1.9 2014/01/21 21:14:58 sf Exp $
.\"
.\" Copyright (c) 2012 Stefan Fritsch <sf@sfritsch.de>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: December 20 2013 $
+.Dd $Mdocdate: January 21 2014 $
.Dt VIRTIO 4
.Os
.Sh NAME
@@ -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
.It Xr vioscsi 4
VirtIO SCSI adapter
.El
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 86c7ba5ab7b..357339c4480 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.356 2014/01/20 18:27:46 jcs Exp $
+# $OpenBSD: GENERIC,v 1.357 2014/01/21 21:14:58 sf Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -608,4 +608,5 @@ 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
vioscsi* at virtio? # Virtio SCSI device
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 411abf4f734..57128fb38a9 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.764 2014/01/20 18:27:46 jcs Exp $
+# $OpenBSD: GENERIC,v 1.765 2014/01/21 21:14:58 sf Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -793,4 +793,5 @@ 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
vioscsi* at virtio? # Virtio SCSI device
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 4965448958f..0ac12c2997d 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.301 2014/01/19 06:04:03 jmatthew Exp $
+# $OpenBSD: files.pci,v 1.302 2014/01/21 21:14:58 sf Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -845,6 +845,10 @@ device viomb
attach viomb at virtio
file dev/pci/viomb.c viomb
+device viornd
+attach viornd at virtio
+file dev/pci/viornd.c viornd
+
device vioscsi: scsi
attach vioscsi at virtio
file dev/pci/vioscsi.c vioscsi
diff --git a/sys/dev/pci/viornd.c b/sys/dev/pci/viornd.c
new file mode 100644
index 00000000000..631db91701e
--- /dev/null
+++ b/sys/dev/pci/viornd.c
@@ -0,0 +1,203 @@
+/* $OpenBSD: viornd.c,v 1.1 2014/01/21 21:14:58 sf Exp $ */
+
+/*
+ * Copyright (c) 2014 Stefan Fritsch <sf@sfritsch.de>
+ *
+ * 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 <sys/pool.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 15 * (1 << interval_shift) seconds.
+ * XXX There should be an API to check if we actually need more entropy.
+ *
+ * The lowest byte in the flags is used for transport specific settings.
+ * Therefore we use the second byte.
+ */
+#define VIORND_INTERVAL_SHIFT(f) ((f >> 8) & 0xf)
+#define VIORND_INTERVAL_SHIFT_DEFAULT 5
+#define VIORND_ONESHOT 0x1000
+#define VIORND_BUFSIZE 16
+
+#define VIORND_DEBUG 0
+
+struct viornd_softc {
+ struct device sc_dev;
+ struct virtio_softc *sc_virtio;
+
+ struct virtqueue sc_vq;
+ int *sc_buf;
+ bus_dmamap_t sc_dmamap;
+
+ unsigned int sc_interval;
+ 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;
+ unsigned int shift;
+
+ vsc->sc_vqs = &sc->sc_vq;
+ vsc->sc_nvqs = 1;
+ vsc->sc_config_change = 0;
+ if (vsc->sc_child != NULL)
+ 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 (sc->sc_dev.dv_cfdata->cf_flags & VIORND_ONESHOT) {
+ sc->sc_interval = 0;
+ } else {
+ shift = VIORND_INTERVAL_SHIFT(sc->sc_dev.dv_cfdata->cf_flags);
+ if (shift == 0)
+ shift = VIORND_INTERVAL_SHIFT_DEFAULT;
+ sc->sc_interval = 15 * (1 << shift);
+ }
+#if VIORND_DEBUG
+ printf(": request interval: %us\n", sc->sc_interval);
+#endif
+
+ sc->sc_buf = dma_alloc(VIORND_BUFSIZE, PR_NOWAIT|PR_ZERO);
+ if (sc->sc_buf == NULL) {
+ printf(": Can't alloc dma buffer\n");
+ goto err;
+ }
+ 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(": Can'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(": Can't load dmamap\n");
+ goto err2;
+ }
+
+ if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, VIORND_BUFSIZE, 1,
+ "Entropy request") != 0) {
+ printf(": Can'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;
+ if (sc->sc_buf != NULL) {
+ dma_free(sc->sc_buf, VIORND_BUFSIZE);
+ sc->sc_buf = NULL;
+ }
+ 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;
+ }
+
+#if VIORND_DEBUG
+ printf("%s: got %d bytes of entropy\n", __func__, len);
+#endif
+ for (i = 0; (i + 1) * sizeof(int) <= len; i++)
+ add_true_randomness(sc->sc_buf[i]);
+
+ if (sc->sc_interval)
+ timeout_add_sec(&sc->sc_tick, sc->sc_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);
+}