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; 116*b0139127SKa Ho Ng struct vi_req req; 1179d0c4e17SPeter Grehan int len; 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*b0139127SKa Ho Ng vq_getchain(vq, &iov, 1, &req); 1289d0c4e17SPeter Grehan 1299d0c4e17SPeter Grehan len = read(sc->vrsc_fd, iov.iov_base, iov.iov_len); 1309d0c4e17SPeter Grehan 131332eff95SVincenzo Maffione DPRINTF(("vtrnd: vtrnd_notify(): %d", len)); 1329d0c4e17SPeter Grehan 1339d0c4e17SPeter Grehan /* Catastrophe if unable to read from /dev/random */ 1349d0c4e17SPeter Grehan assert(len > 0); 1359d0c4e17SPeter Grehan 1369d0c4e17SPeter Grehan /* 1379d0c4e17SPeter Grehan * Release this chain and handle more 1389d0c4e17SPeter Grehan */ 139*b0139127SKa Ho Ng vq_relchain(vq, req.idx, len); 1409d0c4e17SPeter Grehan } 1419d0c4e17SPeter Grehan vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ 1429d0c4e17SPeter Grehan } 1439d0c4e17SPeter Grehan 1449d0c4e17SPeter Grehan 1459d0c4e17SPeter Grehan static int 146621b5090SJohn Baldwin pci_vtrnd_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 1479d0c4e17SPeter Grehan { 1489d0c4e17SPeter Grehan struct pci_vtrnd_softc *sc; 1499d0c4e17SPeter Grehan int fd; 1509d0c4e17SPeter Grehan int len; 1519d0c4e17SPeter Grehan uint8_t v; 15200ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM 15300ef17beSBartek Rutkowski cap_rights_t rights; 15400ef17beSBartek Rutkowski #endif 1559d0c4e17SPeter Grehan 1569d0c4e17SPeter Grehan /* 1579d0c4e17SPeter Grehan * Should always be able to open /dev/random. 1589d0c4e17SPeter Grehan */ 1599d0c4e17SPeter Grehan fd = open("/dev/random", O_RDONLY | O_NONBLOCK); 1609d0c4e17SPeter Grehan 1619d0c4e17SPeter Grehan assert(fd >= 0); 1629d0c4e17SPeter Grehan 16300ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM 16400ef17beSBartek Rutkowski cap_rights_init(&rights, CAP_READ); 165abfa3c39SMarcelo Araujo if (caph_rights_limit(fd, &rights) == -1) 16600ef17beSBartek Rutkowski errx(EX_OSERR, "Unable to apply rights for sandbox"); 16700ef17beSBartek Rutkowski #endif 16800ef17beSBartek Rutkowski 1699d0c4e17SPeter Grehan /* 1709d0c4e17SPeter Grehan * Check that device is seeded and non-blocking. 1719d0c4e17SPeter Grehan */ 1729d0c4e17SPeter Grehan len = read(fd, &v, sizeof(v)); 1739d0c4e17SPeter Grehan if (len <= 0) { 174332eff95SVincenzo Maffione WPRINTF(("vtrnd: /dev/random not ready, read(): %d", len)); 1756c8dae3cSMarcelo Araujo close(fd); 1769d0c4e17SPeter Grehan return (1); 1779d0c4e17SPeter Grehan } 1789d0c4e17SPeter Grehan 179994f858aSXin LI sc = calloc(1, sizeof(struct pci_vtrnd_softc)); 1809d0c4e17SPeter Grehan 1819d0c4e17SPeter Grehan vi_softc_linkup(&sc->vrsc_vs, &vtrnd_vi_consts, sc, pi, &sc->vrsc_vq); 1829d0c4e17SPeter Grehan sc->vrsc_vs.vs_mtx = &sc->vrsc_mtx; 1839d0c4e17SPeter Grehan 1849d0c4e17SPeter Grehan sc->vrsc_vq.vq_qsize = VTRND_RINGSZ; 1859d0c4e17SPeter Grehan 1869d0c4e17SPeter Grehan /* keep /dev/random opened while emulating */ 1879d0c4e17SPeter Grehan sc->vrsc_fd = fd; 1889d0c4e17SPeter Grehan 1899d0c4e17SPeter Grehan /* initialize config space */ 1909d0c4e17SPeter Grehan pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_RANDOM); 1919d0c4e17SPeter Grehan pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 1929d0c4e17SPeter Grehan pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_CRYPTO); 19354ac6f72SKa Ho Ng pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_ENTROPY); 194604b5210SPeter Grehan pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 1959d0c4e17SPeter Grehan 1969d0c4e17SPeter Grehan if (vi_intr_init(&sc->vrsc_vs, 1, fbsdrun_virtio_msix())) 1979d0c4e17SPeter Grehan return (1); 1989d0c4e17SPeter Grehan vi_set_io_bar(&sc->vrsc_vs, 0); 1999d0c4e17SPeter Grehan 2009d0c4e17SPeter Grehan return (0); 2019d0c4e17SPeter Grehan } 2029d0c4e17SPeter Grehan 2039d0c4e17SPeter Grehan 2049d0c4e17SPeter Grehan struct pci_devemu pci_de_vrnd = { 2059d0c4e17SPeter Grehan .pe_emu = "virtio-rnd", 2069d0c4e17SPeter Grehan .pe_init = pci_vtrnd_init, 2079d0c4e17SPeter Grehan .pe_barwrite = vi_pci_write, 208bb481f67SJohn Baldwin .pe_barread = vi_pci_read, 209bb481f67SJohn Baldwin #ifdef BHYVE_SNAPSHOT 210bb481f67SJohn Baldwin .pe_snapshot = vi_pci_snapshot, 211bb481f67SJohn Baldwin #endif 2129d0c4e17SPeter Grehan }; 2139d0c4e17SPeter Grehan PCI_EMUL_SET(pci_de_vrnd); 214