19d0c4e17SPeter Grehan /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
3700ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
3800ef17beSBartek Rutkowski #include <sys/capsicum.h>
3900ef17beSBartek Rutkowski #endif
409d0c4e17SPeter Grehan #include <sys/linker_set.h>
419d0c4e17SPeter Grehan #include <sys/uio.h>
429d0c4e17SPeter Grehan
43abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
44abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
45abfa3c39SMarcelo Araujo #endif
4600ef17beSBartek Rutkowski #include <err.h>
479d0c4e17SPeter Grehan #include <errno.h>
489d0c4e17SPeter Grehan #include <fcntl.h>
499d0c4e17SPeter Grehan #include <stdio.h>
509d0c4e17SPeter Grehan #include <stdlib.h>
519d0c4e17SPeter Grehan #include <string.h>
529d0c4e17SPeter Grehan #include <unistd.h>
539d0c4e17SPeter Grehan #include <assert.h>
549d0c4e17SPeter Grehan #include <pthread.h>
5500ef17beSBartek Rutkowski #include <sysexits.h>
569d0c4e17SPeter Grehan
579d0c4e17SPeter Grehan #include "bhyverun.h"
58332eff95SVincenzo Maffione #include "debug.h"
599d0c4e17SPeter Grehan #include "pci_emul.h"
609d0c4e17SPeter Grehan #include "virtio.h"
619d0c4e17SPeter Grehan
629d0c4e17SPeter Grehan #define VTRND_RINGSZ 64
639d0c4e17SPeter Grehan
649d0c4e17SPeter Grehan
659d0c4e17SPeter Grehan static int pci_vtrnd_debug;
66332eff95SVincenzo Maffione #define DPRINTF(params) if (pci_vtrnd_debug) PRINTLN params
67332eff95SVincenzo Maffione #define WPRINTF(params) PRINTLN params
689d0c4e17SPeter Grehan
699d0c4e17SPeter Grehan /*
709d0c4e17SPeter Grehan * Per-device softc
719d0c4e17SPeter Grehan */
729d0c4e17SPeter Grehan struct pci_vtrnd_softc {
739d0c4e17SPeter Grehan struct virtio_softc vrsc_vs;
749d0c4e17SPeter Grehan struct vqueue_info vrsc_vq;
759d0c4e17SPeter Grehan pthread_mutex_t vrsc_mtx;
769d0c4e17SPeter Grehan uint64_t vrsc_cfg;
779d0c4e17SPeter Grehan int vrsc_fd;
789d0c4e17SPeter Grehan };
799d0c4e17SPeter Grehan
809d0c4e17SPeter Grehan static void pci_vtrnd_reset(void *);
819d0c4e17SPeter Grehan static void pci_vtrnd_notify(void *, struct vqueue_info *);
829d0c4e17SPeter Grehan
839d0c4e17SPeter Grehan static struct virtio_consts vtrnd_vi_consts = {
846cb26162SMark Johnston .vc_name = "vtrnd",
856cb26162SMark Johnston .vc_nvq = 1,
866cb26162SMark Johnston .vc_cfgsize = 0,
876cb26162SMark Johnston .vc_reset = pci_vtrnd_reset,
886cb26162SMark Johnston .vc_qnotify = pci_vtrnd_notify,
896cb26162SMark Johnston .vc_hv_caps = 0,
909d0c4e17SPeter Grehan };
919d0c4e17SPeter Grehan
929d0c4e17SPeter Grehan static void
pci_vtrnd_reset(void * vsc)939d0c4e17SPeter Grehan pci_vtrnd_reset(void *vsc)
949d0c4e17SPeter Grehan {
959d0c4e17SPeter Grehan struct pci_vtrnd_softc *sc;
969d0c4e17SPeter Grehan
979d0c4e17SPeter Grehan sc = vsc;
989d0c4e17SPeter Grehan
99332eff95SVincenzo Maffione DPRINTF(("vtrnd: device reset requested !"));
1009d0c4e17SPeter Grehan vi_reset_dev(&sc->vrsc_vs);
1019d0c4e17SPeter Grehan }
1029d0c4e17SPeter Grehan
1039d0c4e17SPeter Grehan
1049d0c4e17SPeter Grehan static void
pci_vtrnd_notify(void * vsc,struct vqueue_info * vq)1059d0c4e17SPeter Grehan pci_vtrnd_notify(void *vsc, struct vqueue_info *vq)
1069d0c4e17SPeter Grehan {
1079d0c4e17SPeter Grehan struct iovec iov;
1089d0c4e17SPeter Grehan struct pci_vtrnd_softc *sc;
109b0139127SKa Ho Ng struct vi_req req;
11071fbc6faSMark Johnston int len, n;
1119d0c4e17SPeter Grehan
1129d0c4e17SPeter Grehan sc = vsc;
1139d0c4e17SPeter Grehan
1149d0c4e17SPeter Grehan if (sc->vrsc_fd < 0) {
1159d0c4e17SPeter Grehan vq_endchains(vq, 0);
1169d0c4e17SPeter Grehan return;
1179d0c4e17SPeter Grehan }
1189d0c4e17SPeter Grehan
1199d0c4e17SPeter Grehan while (vq_has_descs(vq)) {
12071fbc6faSMark Johnston n = vq_getchain(vq, &iov, 1, &req);
12171fbc6faSMark Johnston assert(n == 1);
1229d0c4e17SPeter Grehan
1239d0c4e17SPeter Grehan len = read(sc->vrsc_fd, iov.iov_base, iov.iov_len);
1249d0c4e17SPeter Grehan
125332eff95SVincenzo Maffione DPRINTF(("vtrnd: vtrnd_notify(): %d", len));
1269d0c4e17SPeter Grehan
1279d0c4e17SPeter Grehan /* Catastrophe if unable to read from /dev/random */
1289d0c4e17SPeter Grehan assert(len > 0);
1299d0c4e17SPeter Grehan
1309d0c4e17SPeter Grehan /*
1319d0c4e17SPeter Grehan * Release this chain and handle more
1329d0c4e17SPeter Grehan */
133b0139127SKa Ho Ng vq_relchain(vq, req.idx, len);
1349d0c4e17SPeter Grehan }
1359d0c4e17SPeter Grehan vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
1369d0c4e17SPeter Grehan }
1379d0c4e17SPeter Grehan
1389d0c4e17SPeter Grehan
1399d0c4e17SPeter Grehan static int
pci_vtrnd_init(struct pci_devinst * pi,nvlist_t * nvl __unused)1406a284cacSJohn Baldwin pci_vtrnd_init(struct pci_devinst *pi, nvlist_t *nvl __unused)
1419d0c4e17SPeter Grehan {
1429d0c4e17SPeter Grehan struct pci_vtrnd_softc *sc;
1439d0c4e17SPeter Grehan int fd;
1449d0c4e17SPeter Grehan int len;
1459d0c4e17SPeter Grehan uint8_t v;
14600ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
14700ef17beSBartek Rutkowski cap_rights_t rights;
14800ef17beSBartek Rutkowski #endif
1499d0c4e17SPeter Grehan
1509d0c4e17SPeter Grehan /*
1519d0c4e17SPeter Grehan * Should always be able to open /dev/random.
1529d0c4e17SPeter Grehan */
1539d0c4e17SPeter Grehan fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
1549d0c4e17SPeter Grehan
1559d0c4e17SPeter Grehan assert(fd >= 0);
1569d0c4e17SPeter Grehan
15700ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
15800ef17beSBartek Rutkowski cap_rights_init(&rights, CAP_READ);
159abfa3c39SMarcelo Araujo if (caph_rights_limit(fd, &rights) == -1)
16000ef17beSBartek Rutkowski errx(EX_OSERR, "Unable to apply rights for sandbox");
16100ef17beSBartek Rutkowski #endif
16200ef17beSBartek Rutkowski
1639d0c4e17SPeter Grehan /*
1649d0c4e17SPeter Grehan * Check that device is seeded and non-blocking.
1659d0c4e17SPeter Grehan */
1669d0c4e17SPeter Grehan len = read(fd, &v, sizeof(v));
1679d0c4e17SPeter Grehan if (len <= 0) {
168332eff95SVincenzo Maffione WPRINTF(("vtrnd: /dev/random not ready, read(): %d", len));
1696c8dae3cSMarcelo Araujo close(fd);
1709d0c4e17SPeter Grehan return (1);
1719d0c4e17SPeter Grehan }
1729d0c4e17SPeter Grehan
173994f858aSXin LI sc = calloc(1, sizeof(struct pci_vtrnd_softc));
1749d0c4e17SPeter Grehan
175f6f357efSAndy Fiddaman pthread_mutex_init(&sc->vrsc_mtx, NULL);
176f6f357efSAndy Fiddaman
1779d0c4e17SPeter Grehan vi_softc_linkup(&sc->vrsc_vs, &vtrnd_vi_consts, sc, pi, &sc->vrsc_vq);
1789d0c4e17SPeter Grehan sc->vrsc_vs.vs_mtx = &sc->vrsc_mtx;
1799d0c4e17SPeter Grehan
1809d0c4e17SPeter Grehan sc->vrsc_vq.vq_qsize = VTRND_RINGSZ;
1819d0c4e17SPeter Grehan
1829d0c4e17SPeter Grehan /* keep /dev/random opened while emulating */
1839d0c4e17SPeter Grehan sc->vrsc_fd = fd;
1849d0c4e17SPeter Grehan
1859d0c4e17SPeter Grehan /* initialize config space */
1869d0c4e17SPeter Grehan pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_RANDOM);
1879d0c4e17SPeter Grehan pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
1889d0c4e17SPeter Grehan pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_CRYPTO);
18954ac6f72SKa Ho Ng pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_ENTROPY);
190604b5210SPeter Grehan pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
1919d0c4e17SPeter Grehan
1929d0c4e17SPeter Grehan if (vi_intr_init(&sc->vrsc_vs, 1, fbsdrun_virtio_msix()))
1939d0c4e17SPeter Grehan return (1);
1949d0c4e17SPeter Grehan vi_set_io_bar(&sc->vrsc_vs, 0);
1959d0c4e17SPeter Grehan
1969d0c4e17SPeter Grehan return (0);
1979d0c4e17SPeter Grehan }
1989d0c4e17SPeter Grehan
1999d0c4e17SPeter Grehan
20037045dfaSMark Johnston static const struct pci_devemu pci_de_vrnd = {
2019d0c4e17SPeter Grehan .pe_emu = "virtio-rnd",
2029d0c4e17SPeter Grehan .pe_init = pci_vtrnd_init,
2039d0c4e17SPeter Grehan .pe_barwrite = vi_pci_write,
204bb481f67SJohn Baldwin .pe_barread = vi_pci_read,
205bb481f67SJohn Baldwin #ifdef BHYVE_SNAPSHOT
206bb481f67SJohn Baldwin .pe_snapshot = vi_pci_snapshot,
207bb481f67SJohn Baldwin #endif
2089d0c4e17SPeter Grehan };
2099d0c4e17SPeter Grehan PCI_EMUL_SET(pci_de_vrnd);
210