2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2014 Nahanni Systems Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * virtio entropy device emulation.
32 * Randomness is sourced from /dev/random which does not block
33 * once it has been seeded at bootup.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
40 #ifndef WITHOUT_CAPSICUM
41 #include <sys/capsicum.h>
43 #include <sys/linker_set.h>
46 #ifndef WITHOUT_CAPSICUM
47 #include <capsicum_helpers.h>
65 #define VTRND_RINGSZ 64
68 static int pci_vtrnd_debug
;
69 #define DPRINTF(params) if (pci_vtrnd_debug) PRINTLN params
70 #define WPRINTF(params) PRINTLN params
75 struct pci_vtrnd_softc
{
76 struct virtio_softc vrsc_vs
;
77 struct vqueue_info vrsc_vq
;
78 pthread_mutex_t vrsc_mtx
;
83 static void pci_vtrnd_reset(void *);
84 static void pci_vtrnd_notify(void *, struct vqueue_info
*);
86 static struct virtio_consts vtrnd_vi_consts
= {
90 .vc_reset
= pci_vtrnd_reset
,
91 .vc_qnotify
= pci_vtrnd_notify
,
96 pci_vtrnd_reset(void *vsc
)
98 struct pci_vtrnd_softc
*sc
;
102 DPRINTF(("vtrnd: device reset requested !"));
103 vi_reset_dev(&sc
->vrsc_vs
);
108 pci_vtrnd_notify(void *vsc
, struct vqueue_info
*vq
)
111 struct pci_vtrnd_softc
*sc
;
117 if (sc
->vrsc_fd
< 0) {
122 while (vq_has_descs(vq
)) {
123 n
= vq_getchain(vq
, &iov
, 1, &req
);
126 len
= read(sc
->vrsc_fd
, iov
.iov_base
, iov
.iov_len
);
128 DPRINTF(("vtrnd: vtrnd_notify(): %d", len
));
130 /* Catastrophe if unable to read from /dev/random */
134 * Release this chain and handle more
136 vq_relchain(vq
, req
.idx
, len
);
138 vq_endchains(vq
, 1); /* Generate interrupt if appropriate. */
143 pci_vtrnd_init(struct vmctx
*ctx __unused
, struct pci_devinst
*pi
,
144 nvlist_t
*nvl __unused
)
146 struct pci_vtrnd_softc
*sc
;
150 #ifndef WITHOUT_CAPSICUM
155 * Should always be able to open /dev/random.
157 fd
= open("/dev/random", O_RDONLY
| O_NONBLOCK
);
161 #ifndef WITHOUT_CAPSICUM
162 cap_rights_init(&rights
, CAP_READ
);
163 if (caph_rights_limit(fd
, &rights
) == -1)
164 errx(EX_OSERR
, "Unable to apply rights for sandbox");
168 * Check that device is seeded and non-blocking.
170 len
= read(fd
, &v
, sizeof(v
));
172 WPRINTF(("vtrnd: /dev/random not ready, read(): %d", len
));
177 sc
= calloc(1, sizeof(struct pci_vtrnd_softc
));
179 pthread_mutex_init(&sc
->vrsc_mtx
, NULL
);
181 vi_softc_linkup(&sc
->vrsc_vs
, &vtrnd_vi_consts
, sc
, pi
, &sc
->vrsc_vq
);
182 sc
->vrsc_vs
.vs_mtx
= &sc
->vrsc_mtx
;
184 sc
->vrsc_vq
.vq_qsize
= VTRND_RINGSZ
;
186 /* keep /dev/random opened while emulating */
189 /* initialize config space */
190 pci_set_cfgdata16(pi
, PCIR_DEVICE
, VIRTIO_DEV_RANDOM
);
191 pci_set_cfgdata16(pi
, PCIR_VENDOR
, VIRTIO_VENDOR
);
192 pci_set_cfgdata8(pi
, PCIR_CLASS
, PCIC_CRYPTO
);
193 pci_set_cfgdata16(pi
, PCIR_SUBDEV_0
, VIRTIO_ID_ENTROPY
);
194 pci_set_cfgdata16(pi
, PCIR_SUBVEND_0
, VIRTIO_VENDOR
);
196 if (vi_intr_init(&sc
->vrsc_vs
, 1, fbsdrun_virtio_msix()))
198 vi_set_io_bar(&sc
->vrsc_vs
, 0);
204 static const struct pci_devemu pci_de_vrnd
= {
205 .pe_emu
= "virtio-rnd",
206 .pe_init
= pci_vtrnd_init
,
207 .pe_barwrite
= vi_pci_write
,
208 .pe_barread
= vi_pci_read
,
210 PCI_EMUL_SET(pci_de_vrnd
);