hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/char/hw_random/virtio-rng.c
....@@ -1,22 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Randomness driver for virtio
34 * Copyright (C) 2007, 2008 Rusty Russell IBM Corporation
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation; either version 2 of the License, or
8
- * (at your option) any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program; if not, write to the Free Software
17
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
185 */
196
7
+#include <asm/barrier.h>
208 #include <linux/err.h>
219 #include <linux/hw_random.h>
2210 #include <linux/scatterlist.h>
....@@ -24,77 +12,118 @@
2412 #include <linux/virtio.h>
2513 #include <linux/virtio_rng.h>
2614 #include <linux/module.h>
15
+#include <linux/slab.h>
2716
2817 static DEFINE_IDA(rng_index_ida);
2918
3019 struct virtrng_info {
3120 struct hwrng hwrng;
3221 struct virtqueue *vq;
33
- struct completion have_data;
3422 char name[25];
35
- unsigned int data_avail;
3623 int index;
37
- bool busy;
3824 bool hwrng_register_done;
3925 bool hwrng_removed;
26
+ /* data transfer */
27
+ struct completion have_data;
28
+ unsigned int data_avail;
29
+ unsigned int data_idx;
30
+ /* minimal size returned by rng_buffer_size() */
31
+#if SMP_CACHE_BYTES < 32
32
+ u8 data[32];
33
+#else
34
+ u8 data[SMP_CACHE_BYTES];
35
+#endif
4036 };
4137
4238 static void random_recv_done(struct virtqueue *vq)
4339 {
4440 struct virtrng_info *vi = vq->vdev->priv;
41
+ unsigned int len;
4542
4643 /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
47
- if (!virtqueue_get_buf(vi->vq, &vi->data_avail))
44
+ if (!virtqueue_get_buf(vi->vq, &len))
4845 return;
4946
47
+ smp_store_release(&vi->data_avail, len);
5048 complete(&vi->have_data);
5149 }
5250
53
-/* The host will fill any buffer we give it with sweet, sweet randomness. */
54
-static void register_buffer(struct virtrng_info *vi, u8 *buf, size_t size)
51
+static void request_entropy(struct virtrng_info *vi)
5552 {
5653 struct scatterlist sg;
5754
58
- sg_init_one(&sg, buf, size);
55
+ reinit_completion(&vi->have_data);
56
+ vi->data_idx = 0;
57
+
58
+ sg_init_one(&sg, vi->data, sizeof(vi->data));
5959
6060 /* There should always be room for one buffer. */
61
- virtqueue_add_inbuf(vi->vq, &sg, 1, buf, GFP_KERNEL);
61
+ virtqueue_add_inbuf(vi->vq, &sg, 1, vi->data, GFP_KERNEL);
6262
6363 virtqueue_kick(vi->vq);
64
+}
65
+
66
+static unsigned int copy_data(struct virtrng_info *vi, void *buf,
67
+ unsigned int size)
68
+{
69
+ size = min_t(unsigned int, size, vi->data_avail);
70
+ memcpy(buf, vi->data + vi->data_idx, size);
71
+ vi->data_idx += size;
72
+ vi->data_avail -= size;
73
+ if (vi->data_avail == 0)
74
+ request_entropy(vi);
75
+ return size;
6476 }
6577
6678 static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
6779 {
6880 int ret;
6981 struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
82
+ unsigned int chunk;
83
+ size_t read;
7084
7185 if (vi->hwrng_removed)
7286 return -ENODEV;
7387
74
- if (!vi->busy) {
75
- vi->busy = true;
76
- reinit_completion(&vi->have_data);
77
- register_buffer(vi, buf, size);
88
+ read = 0;
89
+
90
+ /* copy available data */
91
+ if (smp_load_acquire(&vi->data_avail)) {
92
+ chunk = copy_data(vi, buf, size);
93
+ size -= chunk;
94
+ read += chunk;
7895 }
7996
8097 if (!wait)
81
- return 0;
98
+ return read;
8299
83
- ret = wait_for_completion_killable(&vi->have_data);
84
- if (ret < 0)
85
- return ret;
100
+ /* We have already copied available entropy,
101
+ * so either size is 0 or data_avail is 0
102
+ */
103
+ while (size != 0) {
104
+ /* data_avail is 0 but a request is pending */
105
+ ret = wait_for_completion_killable(&vi->have_data);
106
+ if (ret < 0)
107
+ return ret;
108
+ /* if vi->data_avail is 0, we have been interrupted
109
+ * by a cleanup, but buffer stays in the queue
110
+ */
111
+ if (vi->data_avail == 0)
112
+ return read;
86113
87
- vi->busy = false;
114
+ chunk = copy_data(vi, buf + read, size);
115
+ size -= chunk;
116
+ read += chunk;
117
+ }
88118
89
- return vi->data_avail;
119
+ return read;
90120 }
91121
92122 static void virtio_cleanup(struct hwrng *rng)
93123 {
94124 struct virtrng_info *vi = (struct virtrng_info *)rng->priv;
95125
96
- if (vi->busy)
97
- wait_for_completion(&vi->have_data);
126
+ complete(&vi->have_data);
98127 }
99128
100129 static int probe_common(struct virtio_device *vdev)
....@@ -130,6 +159,9 @@
130159 goto err_find;
131160 }
132161
162
+ /* we always have a pending entropy request */
163
+ request_entropy(vi);
164
+
133165 return 0;
134166
135167 err_find:
....@@ -145,9 +177,9 @@
145177
146178 vi->hwrng_removed = true;
147179 vi->data_avail = 0;
180
+ vi->data_idx = 0;
148181 complete(&vi->have_data);
149182 vdev->config->reset(vdev);
150
- vi->busy = false;
151183 if (vi->hwrng_register_done)
152184 hwrng_unregister(&vi->hwrng);
153185 vdev->config->del_vqs(vdev);
....@@ -207,7 +239,7 @@
207239 }
208240 #endif
209241
210
-static struct virtio_device_id id_table[] = {
242
+static const struct virtio_device_id id_table[] = {
211243 { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
212244 { 0 },
213245 };