1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2013, Bryan Venteicher <[email protected]>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
12 * disclaimer.
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.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* Driver for VirtIO entropy device. */
30
31 #include <sys/cdefs.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/eventhandler.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/sglist.h>
39 #include <sys/random.h>
40 #include <sys/stdatomic.h>
41
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/bus.h>
45
46 #include <dev/random/randomdev.h>
47 #include <dev/random/random_harvestq.h>
48 #include <dev/virtio/virtio.h>
49 #include <dev/virtio/virtqueue.h>
50
51 struct vtrnd_softc {
52 device_t vtrnd_dev;
53 uint64_t vtrnd_features;
54 struct virtqueue *vtrnd_vq;
55 eventhandler_tag eh;
56 bool inactive;
57 struct sglist *vtrnd_sg;
58 uint32_t *vtrnd_value;
59 };
60
61 static int vtrnd_modevent(module_t, int, void *);
62
63 static int vtrnd_probe(device_t);
64 static int vtrnd_attach(device_t);
65 static int vtrnd_detach(device_t);
66 static int vtrnd_shutdown(device_t);
67
68 static int vtrnd_negotiate_features(struct vtrnd_softc *);
69 static int vtrnd_setup_features(struct vtrnd_softc *);
70 static int vtrnd_alloc_virtqueue(struct vtrnd_softc *);
71 static int vtrnd_harvest(struct vtrnd_softc *, void *, size_t *);
72 static void vtrnd_enqueue(struct vtrnd_softc *sc);
73 static unsigned vtrnd_read(void *, unsigned);
74
75 #define VTRND_FEATURES 0
76
77 static struct virtio_feature_desc vtrnd_feature_desc[] = {
78 { 0, NULL }
79 };
80
81 static struct random_source random_vtrnd = {
82 .rs_ident = "VirtIO Entropy Adapter",
83 .rs_source = RANDOM_PURE_VIRTIO,
84 .rs_read = vtrnd_read,
85 };
86
87 /* Kludge for API limitations of random(4). */
88 static _Atomic(struct vtrnd_softc *) g_vtrnd_softc;
89
90 static device_method_t vtrnd_methods[] = {
91 /* Device methods. */
92 DEVMETHOD(device_probe, vtrnd_probe),
93 DEVMETHOD(device_attach, vtrnd_attach),
94 DEVMETHOD(device_detach, vtrnd_detach),
95 DEVMETHOD(device_shutdown, vtrnd_shutdown),
96
97 DEVMETHOD_END
98 };
99
100 static driver_t vtrnd_driver = {
101 "vtrnd",
102 vtrnd_methods,
103 sizeof(struct vtrnd_softc)
104 };
105
106 VIRTIO_DRIVER_MODULE(virtio_random, vtrnd_driver, vtrnd_modevent, NULL);
107 MODULE_VERSION(virtio_random, 1);
108 MODULE_DEPEND(virtio_random, virtio, 1, 1, 1);
109 MODULE_DEPEND(virtio_random, random_device, 1, 1, 1);
110
111 VIRTIO_SIMPLE_PNPINFO(virtio_random, VIRTIO_ID_ENTROPY,
112 "VirtIO Entropy Adapter");
113
114 static int
vtrnd_modevent(module_t mod,int type,void * unused)115 vtrnd_modevent(module_t mod, int type, void *unused)
116 {
117 int error;
118
119 switch (type) {
120 case MOD_LOAD:
121 case MOD_QUIESCE:
122 case MOD_UNLOAD:
123 case MOD_SHUTDOWN:
124 error = 0;
125 break;
126 default:
127 error = EOPNOTSUPP;
128 break;
129 }
130
131 return (error);
132 }
133
134 static int
vtrnd_probe(device_t dev)135 vtrnd_probe(device_t dev)
136 {
137 return (VIRTIO_SIMPLE_PROBE(dev, virtio_random));
138 }
139
140 static int
vtrnd_attach(device_t dev)141 vtrnd_attach(device_t dev)
142 {
143 struct vtrnd_softc *sc, *exp;
144 size_t len;
145 int error;
146
147 sc = device_get_softc(dev);
148 sc->vtrnd_dev = dev;
149 virtio_set_feature_desc(dev, vtrnd_feature_desc);
150
151 len = sizeof(*sc->vtrnd_value) * HARVESTSIZE;
152 sc->vtrnd_value = malloc_aligned(len, len, M_DEVBUF, M_WAITOK);
153 sc->vtrnd_sg = sglist_build(sc->vtrnd_value, len, M_WAITOK);
154
155 error = vtrnd_setup_features(sc);
156 if (error) {
157 device_printf(dev, "cannot setup features\n");
158 goto fail;
159 }
160
161 error = vtrnd_alloc_virtqueue(sc);
162 if (error) {
163 device_printf(dev, "cannot allocate virtqueue\n");
164 goto fail;
165 }
166
167 exp = NULL;
168 if (!atomic_compare_exchange_strong_explicit(&g_vtrnd_softc, &exp, sc,
169 memory_order_release, memory_order_acquire)) {
170 error = EEXIST;
171 goto fail;
172 }
173
174 sc->eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
175 vtrnd_shutdown, dev, SHUTDOWN_PRI_LAST + 1); /* ??? */
176 if (sc->eh == NULL) {
177 device_printf(dev, "Shutdown event registration failed\n");
178 error = ENXIO;
179 goto fail;
180 }
181
182 sc->inactive = false;
183 random_source_register(&random_vtrnd);
184
185 vtrnd_enqueue(sc);
186
187 fail:
188 if (error)
189 vtrnd_detach(dev);
190
191 return (error);
192 }
193
194 static int
vtrnd_detach(device_t dev)195 vtrnd_detach(device_t dev)
196 {
197 struct vtrnd_softc *sc;
198 uint32_t rdlen;
199
200 sc = device_get_softc(dev);
201 KASSERT(
202 atomic_load_explicit(&g_vtrnd_softc, memory_order_acquire) == sc,
203 ("only one global instance at a time"));
204
205 sc->inactive = true;
206 if (sc->eh != NULL) {
207 EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->eh);
208 sc->eh = NULL;
209 }
210 random_source_deregister(&random_vtrnd);
211
212 /* clear the queue */
213 virtqueue_poll(sc->vtrnd_vq, &rdlen);
214
215 atomic_store_explicit(&g_vtrnd_softc, NULL, memory_order_release);
216 sglist_free(sc->vtrnd_sg);
217 zfree(sc->vtrnd_value, M_DEVBUF);
218 return (0);
219 }
220
221 static int
vtrnd_shutdown(device_t dev)222 vtrnd_shutdown(device_t dev)
223 {
224 struct vtrnd_softc *sc;
225
226 sc = device_get_softc(dev);
227 sc->inactive = true;
228
229 return(0);
230 }
231
232 static int
vtrnd_negotiate_features(struct vtrnd_softc * sc)233 vtrnd_negotiate_features(struct vtrnd_softc *sc)
234 {
235 device_t dev;
236 uint64_t features;
237
238 dev = sc->vtrnd_dev;
239 features = VTRND_FEATURES;
240
241 sc->vtrnd_features = virtio_negotiate_features(dev, features);
242 return (virtio_finalize_features(dev));
243 }
244
245 static int
vtrnd_setup_features(struct vtrnd_softc * sc)246 vtrnd_setup_features(struct vtrnd_softc *sc)
247 {
248 int error;
249
250 error = vtrnd_negotiate_features(sc);
251 if (error)
252 return (error);
253
254 return (0);
255 }
256
257 static int
vtrnd_alloc_virtqueue(struct vtrnd_softc * sc)258 vtrnd_alloc_virtqueue(struct vtrnd_softc *sc)
259 {
260 device_t dev;
261 struct vq_alloc_info vq_info;
262
263 dev = sc->vtrnd_dev;
264
265 VQ_ALLOC_INFO_INIT(&vq_info, 0, NULL, sc, &sc->vtrnd_vq,
266 "%s request", device_get_nameunit(dev));
267
268 return (virtio_alloc_virtqueues(dev, 0, 1, &vq_info));
269 }
270
271 static void
vtrnd_enqueue(struct vtrnd_softc * sc)272 vtrnd_enqueue(struct vtrnd_softc *sc)
273 {
274 struct virtqueue *vq;
275 int error __diagused;
276
277 vq = sc->vtrnd_vq;
278
279 KASSERT(virtqueue_empty(vq), ("%s: non-empty queue", __func__));
280
281 error = virtqueue_enqueue(vq, sc, sc->vtrnd_sg, 0, 1);
282 KASSERT(error == 0, ("%s: virtqueue_enqueue returned error: %d",
283 __func__, error));
284
285 virtqueue_notify(vq);
286 }
287
288 static int
vtrnd_harvest(struct vtrnd_softc * sc,void * buf,size_t * sz)289 vtrnd_harvest(struct vtrnd_softc *sc, void *buf, size_t *sz)
290 {
291 struct virtqueue *vq;
292 void *cookie;
293 uint32_t rdlen;
294
295 if (sc->inactive)
296 return (EDEADLK);
297
298 vq = sc->vtrnd_vq;
299
300 cookie = virtqueue_dequeue(vq, &rdlen);
301 if (cookie == NULL)
302 return (EAGAIN);
303 KASSERT(cookie == sc, ("%s: cookie mismatch", __func__));
304
305 *sz = MIN(rdlen, *sz);
306 memcpy(buf, sc->vtrnd_value, *sz);
307
308 vtrnd_enqueue(sc);
309
310 return (0);
311 }
312
313 static unsigned
vtrnd_read(void * buf,unsigned usz)314 vtrnd_read(void *buf, unsigned usz)
315 {
316 struct vtrnd_softc *sc;
317 size_t sz;
318 int error;
319
320 sc = g_vtrnd_softc;
321 if (sc == NULL)
322 return (0);
323
324 sz = usz;
325 error = vtrnd_harvest(sc, buf, &sz);
326 if (error != 0)
327 return (0);
328
329 return (sz);
330 }
331