xref: /freebsd/usr.sbin/bhyve/pci_virtio_rnd.c (revision 71fbc6faed62e8eb5864f7c40839740f5e9f5558)
19d0c4e17SPeter Grehan /*-
2ce80faa4SMarcelo Araujo  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3ce80faa4SMarcelo Araujo  *
49d0c4e17SPeter Grehan  * Copyright (c) 2014 Nahanni Systems Inc.
59d0c4e17SPeter Grehan  * All rights reserved.
69d0c4e17SPeter Grehan  *
79d0c4e17SPeter Grehan  * Redistribution and use in source and binary forms, with or without
89d0c4e17SPeter Grehan  * modification, are permitted provided that the following conditions
99d0c4e17SPeter Grehan  * are met:
109d0c4e17SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
119d0c4e17SPeter Grehan  *    notice, this list of conditions and the following disclaimer
129d0c4e17SPeter Grehan  *    in this position and unchanged.
139d0c4e17SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
149d0c4e17SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
159d0c4e17SPeter Grehan  *    documentation and/or other materials provided with the distribution.
169d0c4e17SPeter Grehan  *
179d0c4e17SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189d0c4e17SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199d0c4e17SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209d0c4e17SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
219d0c4e17SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229d0c4e17SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239d0c4e17SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249d0c4e17SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259d0c4e17SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269d0c4e17SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279d0c4e17SPeter Grehan  * SUCH DAMAGE.
289d0c4e17SPeter Grehan  */
299d0c4e17SPeter Grehan 
309d0c4e17SPeter Grehan /*
319d0c4e17SPeter Grehan  * virtio entropy device emulation.
329d0c4e17SPeter Grehan  * Randomness is sourced from /dev/random which does not block
339d0c4e17SPeter Grehan  * once it has been seeded at bootup.
349d0c4e17SPeter Grehan  */
359d0c4e17SPeter Grehan 
369d0c4e17SPeter Grehan #include <sys/cdefs.h>
379d0c4e17SPeter Grehan __FBSDID("$FreeBSD$");
389d0c4e17SPeter Grehan 
399d0c4e17SPeter Grehan #include <sys/param.h>
4000ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
4100ef17beSBartek Rutkowski #include <sys/capsicum.h>
4200ef17beSBartek Rutkowski #endif
439d0c4e17SPeter Grehan #include <sys/linker_set.h>
449d0c4e17SPeter Grehan #include <sys/uio.h>
459d0c4e17SPeter Grehan 
46abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
47abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
48abfa3c39SMarcelo Araujo #endif
4900ef17beSBartek Rutkowski #include <err.h>
509d0c4e17SPeter Grehan #include <errno.h>
519d0c4e17SPeter Grehan #include <fcntl.h>
529d0c4e17SPeter Grehan #include <stdio.h>
539d0c4e17SPeter Grehan #include <stdlib.h>
549d0c4e17SPeter Grehan #include <string.h>
559d0c4e17SPeter Grehan #include <unistd.h>
569d0c4e17SPeter Grehan #include <assert.h>
579d0c4e17SPeter Grehan #include <pthread.h>
5800ef17beSBartek Rutkowski #include <sysexits.h>
599d0c4e17SPeter Grehan 
609d0c4e17SPeter Grehan #include "bhyverun.h"
61332eff95SVincenzo Maffione #include "debug.h"
629d0c4e17SPeter Grehan #include "pci_emul.h"
639d0c4e17SPeter Grehan #include "virtio.h"
649d0c4e17SPeter Grehan 
659d0c4e17SPeter Grehan #define VTRND_RINGSZ	64
669d0c4e17SPeter Grehan 
679d0c4e17SPeter Grehan 
689d0c4e17SPeter Grehan static int pci_vtrnd_debug;
69332eff95SVincenzo Maffione #define DPRINTF(params) if (pci_vtrnd_debug) PRINTLN params
70332eff95SVincenzo Maffione #define WPRINTF(params) PRINTLN params
719d0c4e17SPeter Grehan 
729d0c4e17SPeter Grehan /*
739d0c4e17SPeter Grehan  * Per-device softc
749d0c4e17SPeter Grehan  */
759d0c4e17SPeter Grehan struct pci_vtrnd_softc {
769d0c4e17SPeter Grehan 	struct virtio_softc vrsc_vs;
779d0c4e17SPeter Grehan 	struct vqueue_info  vrsc_vq;
789d0c4e17SPeter Grehan 	pthread_mutex_t     vrsc_mtx;
799d0c4e17SPeter Grehan 	uint64_t            vrsc_cfg;
809d0c4e17SPeter Grehan 	int                 vrsc_fd;
819d0c4e17SPeter Grehan };
829d0c4e17SPeter Grehan 
839d0c4e17SPeter Grehan static void pci_vtrnd_reset(void *);
849d0c4e17SPeter Grehan static void pci_vtrnd_notify(void *, struct vqueue_info *);
859d0c4e17SPeter Grehan 
869d0c4e17SPeter Grehan static struct virtio_consts vtrnd_vi_consts = {
879d0c4e17SPeter Grehan 	"vtrnd",		/* our name */
889d0c4e17SPeter Grehan 	1,			/* we support 1 virtqueue */
899d0c4e17SPeter Grehan 	0,			/* config reg size */
909d0c4e17SPeter Grehan 	pci_vtrnd_reset,	/* reset */
919d0c4e17SPeter Grehan 	pci_vtrnd_notify,	/* device-wide qnotify */
929d0c4e17SPeter Grehan 	NULL,			/* read virtio config */
939d0c4e17SPeter Grehan 	NULL,			/* write virtio config */
94e18f344bSPeter Grehan 	NULL,			/* apply negotiated features */
959d0c4e17SPeter Grehan 	0,			/* our capabilities */
969d0c4e17SPeter Grehan };
979d0c4e17SPeter Grehan 
989d0c4e17SPeter Grehan 
999d0c4e17SPeter Grehan static void
1009d0c4e17SPeter Grehan pci_vtrnd_reset(void *vsc)
1019d0c4e17SPeter Grehan {
1029d0c4e17SPeter Grehan 	struct pci_vtrnd_softc *sc;
1039d0c4e17SPeter Grehan 
1049d0c4e17SPeter Grehan 	sc = vsc;
1059d0c4e17SPeter Grehan 
106332eff95SVincenzo Maffione 	DPRINTF(("vtrnd: device reset requested !"));
1079d0c4e17SPeter Grehan 	vi_reset_dev(&sc->vrsc_vs);
1089d0c4e17SPeter Grehan }
1099d0c4e17SPeter Grehan 
1109d0c4e17SPeter Grehan 
1119d0c4e17SPeter Grehan static void
1129d0c4e17SPeter Grehan pci_vtrnd_notify(void *vsc, struct vqueue_info *vq)
1139d0c4e17SPeter Grehan {
1149d0c4e17SPeter Grehan 	struct iovec iov;
1159d0c4e17SPeter Grehan 	struct pci_vtrnd_softc *sc;
116b0139127SKa Ho Ng 	struct vi_req req;
117*71fbc6faSMark Johnston 	int len, n;
1189d0c4e17SPeter Grehan 
1199d0c4e17SPeter Grehan 	sc = vsc;
1209d0c4e17SPeter Grehan 
1219d0c4e17SPeter Grehan 	if (sc->vrsc_fd < 0) {
1229d0c4e17SPeter Grehan 		vq_endchains(vq, 0);
1239d0c4e17SPeter Grehan 		return;
1249d0c4e17SPeter Grehan 	}
1259d0c4e17SPeter Grehan 
1269d0c4e17SPeter Grehan 	while (vq_has_descs(vq)) {
127*71fbc6faSMark Johnston 		n = vq_getchain(vq, &iov, 1, &req);
128*71fbc6faSMark Johnston 		assert(n == 1);
1299d0c4e17SPeter Grehan 
1309d0c4e17SPeter Grehan 		len = read(sc->vrsc_fd, iov.iov_base, iov.iov_len);
1319d0c4e17SPeter Grehan 
132332eff95SVincenzo Maffione 		DPRINTF(("vtrnd: vtrnd_notify(): %d", len));
1339d0c4e17SPeter Grehan 
1349d0c4e17SPeter Grehan 		/* Catastrophe if unable to read from /dev/random */
1359d0c4e17SPeter Grehan 		assert(len > 0);
1369d0c4e17SPeter Grehan 
1379d0c4e17SPeter Grehan 		/*
1389d0c4e17SPeter Grehan 		 * Release this chain and handle more
1399d0c4e17SPeter Grehan 		 */
140b0139127SKa Ho Ng 		vq_relchain(vq, req.idx, len);
1419d0c4e17SPeter Grehan 	}
1429d0c4e17SPeter Grehan 	vq_endchains(vq, 1);	/* Generate interrupt if appropriate. */
1439d0c4e17SPeter Grehan }
1449d0c4e17SPeter Grehan 
1459d0c4e17SPeter Grehan 
1469d0c4e17SPeter Grehan static int
147621b5090SJohn Baldwin pci_vtrnd_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
1489d0c4e17SPeter Grehan {
1499d0c4e17SPeter Grehan 	struct pci_vtrnd_softc *sc;
1509d0c4e17SPeter Grehan 	int fd;
1519d0c4e17SPeter Grehan 	int len;
1529d0c4e17SPeter Grehan 	uint8_t v;
15300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
15400ef17beSBartek Rutkowski 	cap_rights_t rights;
15500ef17beSBartek Rutkowski #endif
1569d0c4e17SPeter Grehan 
1579d0c4e17SPeter Grehan 	/*
1589d0c4e17SPeter Grehan 	 * Should always be able to open /dev/random.
1599d0c4e17SPeter Grehan 	 */
1609d0c4e17SPeter Grehan 	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
1619d0c4e17SPeter Grehan 
1629d0c4e17SPeter Grehan 	assert(fd >= 0);
1639d0c4e17SPeter Grehan 
16400ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
16500ef17beSBartek Rutkowski 	cap_rights_init(&rights, CAP_READ);
166abfa3c39SMarcelo Araujo 	if (caph_rights_limit(fd, &rights) == -1)
16700ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
16800ef17beSBartek Rutkowski #endif
16900ef17beSBartek Rutkowski 
1709d0c4e17SPeter Grehan 	/*
1719d0c4e17SPeter Grehan 	 * Check that device is seeded and non-blocking.
1729d0c4e17SPeter Grehan 	 */
1739d0c4e17SPeter Grehan 	len = read(fd, &v, sizeof(v));
1749d0c4e17SPeter Grehan 	if (len <= 0) {
175332eff95SVincenzo Maffione 		WPRINTF(("vtrnd: /dev/random not ready, read(): %d", len));
1766c8dae3cSMarcelo Araujo 		close(fd);
1779d0c4e17SPeter Grehan 		return (1);
1789d0c4e17SPeter Grehan 	}
1799d0c4e17SPeter Grehan 
180994f858aSXin LI 	sc = calloc(1, sizeof(struct pci_vtrnd_softc));
1819d0c4e17SPeter Grehan 
1829d0c4e17SPeter Grehan 	vi_softc_linkup(&sc->vrsc_vs, &vtrnd_vi_consts, sc, pi, &sc->vrsc_vq);
1839d0c4e17SPeter Grehan 	sc->vrsc_vs.vs_mtx = &sc->vrsc_mtx;
1849d0c4e17SPeter Grehan 
1859d0c4e17SPeter Grehan 	sc->vrsc_vq.vq_qsize = VTRND_RINGSZ;
1869d0c4e17SPeter Grehan 
1879d0c4e17SPeter Grehan 	/* keep /dev/random opened while emulating */
1889d0c4e17SPeter Grehan 	sc->vrsc_fd = fd;
1899d0c4e17SPeter Grehan 
1909d0c4e17SPeter Grehan 	/* initialize config space */
1919d0c4e17SPeter Grehan 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_RANDOM);
1929d0c4e17SPeter Grehan 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
1939d0c4e17SPeter Grehan 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_CRYPTO);
19454ac6f72SKa Ho Ng 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_ENTROPY);
195604b5210SPeter Grehan 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
1969d0c4e17SPeter Grehan 
1979d0c4e17SPeter Grehan 	if (vi_intr_init(&sc->vrsc_vs, 1, fbsdrun_virtio_msix()))
1989d0c4e17SPeter Grehan 		return (1);
1999d0c4e17SPeter Grehan 	vi_set_io_bar(&sc->vrsc_vs, 0);
2009d0c4e17SPeter Grehan 
2019d0c4e17SPeter Grehan 	return (0);
2029d0c4e17SPeter Grehan }
2039d0c4e17SPeter Grehan 
2049d0c4e17SPeter Grehan 
2059d0c4e17SPeter Grehan struct pci_devemu pci_de_vrnd = {
2069d0c4e17SPeter Grehan 	.pe_emu =	"virtio-rnd",
2079d0c4e17SPeter Grehan 	.pe_init =	pci_vtrnd_init,
2089d0c4e17SPeter Grehan 	.pe_barwrite =	vi_pci_write,
209bb481f67SJohn Baldwin 	.pe_barread =	vi_pci_read,
210bb481f67SJohn Baldwin #ifdef BHYVE_SNAPSHOT
211bb481f67SJohn Baldwin 	.pe_snapshot =	vi_pci_snapshot,
212bb481f67SJohn Baldwin #endif
2139d0c4e17SPeter Grehan };
2149d0c4e17SPeter Grehan PCI_EMUL_SET(pci_de_vrnd);
215