Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/hw_random/core.c
15111 views
1
/*
2
Added support for the AMD Geode LX RNG
3
(c) Copyright 2004-2005 Advanced Micro Devices, Inc.
4
5
derived from
6
7
Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
8
(c) Copyright 2003 Red Hat Inc <[email protected]>
9
10
derived from
11
12
Hardware driver for the AMD 768 Random Number Generator (RNG)
13
(c) Copyright 2001 Red Hat Inc <[email protected]>
14
15
derived from
16
17
Hardware driver for Intel i810 Random Number Generator (RNG)
18
Copyright 2000,2001 Jeff Garzik <[email protected]>
19
Copyright 2000,2001 Philipp Rumpf <[email protected]>
20
21
Added generic RNG API
22
Copyright 2006 Michael Buesch <[email protected]>
23
Copyright 2005 (c) MontaVista Software, Inc.
24
25
Please read Documentation/hw_random.txt for details on use.
26
27
----------------------------------------------------------
28
This software may be used and distributed according to the terms
29
of the GNU General Public License, incorporated herein by reference.
30
31
*/
32
33
34
#include <linux/device.h>
35
#include <linux/hw_random.h>
36
#include <linux/module.h>
37
#include <linux/kernel.h>
38
#include <linux/fs.h>
39
#include <linux/sched.h>
40
#include <linux/init.h>
41
#include <linux/miscdevice.h>
42
#include <linux/delay.h>
43
#include <asm/uaccess.h>
44
45
46
#define RNG_MODULE_NAME "hw_random"
47
#define PFX RNG_MODULE_NAME ": "
48
#define RNG_MISCDEV_MINOR 183 /* official */
49
50
51
static struct hwrng *current_rng;
52
static LIST_HEAD(rng_list);
53
static DEFINE_MUTEX(rng_mutex);
54
static int data_avail;
55
static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES]
56
__cacheline_aligned;
57
58
static inline int hwrng_init(struct hwrng *rng)
59
{
60
if (!rng->init)
61
return 0;
62
return rng->init(rng);
63
}
64
65
static inline void hwrng_cleanup(struct hwrng *rng)
66
{
67
if (rng && rng->cleanup)
68
rng->cleanup(rng);
69
}
70
71
static int rng_dev_open(struct inode *inode, struct file *filp)
72
{
73
/* enforce read-only access to this chrdev */
74
if ((filp->f_mode & FMODE_READ) == 0)
75
return -EINVAL;
76
if (filp->f_mode & FMODE_WRITE)
77
return -EINVAL;
78
return 0;
79
}
80
81
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
82
int wait) {
83
int present;
84
85
if (rng->read)
86
return rng->read(rng, (void *)buffer, size, wait);
87
88
if (rng->data_present)
89
present = rng->data_present(rng, wait);
90
else
91
present = 1;
92
93
if (present)
94
return rng->data_read(rng, (u32 *)buffer);
95
96
return 0;
97
}
98
99
static ssize_t rng_dev_read(struct file *filp, char __user *buf,
100
size_t size, loff_t *offp)
101
{
102
ssize_t ret = 0;
103
int err = 0;
104
int bytes_read, len;
105
106
while (size) {
107
if (mutex_lock_interruptible(&rng_mutex)) {
108
err = -ERESTARTSYS;
109
goto out;
110
}
111
112
if (!current_rng) {
113
err = -ENODEV;
114
goto out_unlock;
115
}
116
117
if (!data_avail) {
118
bytes_read = rng_get_data(current_rng, rng_buffer,
119
sizeof(rng_buffer),
120
!(filp->f_flags & O_NONBLOCK));
121
if (bytes_read < 0) {
122
err = bytes_read;
123
goto out_unlock;
124
}
125
data_avail = bytes_read;
126
}
127
128
if (!data_avail) {
129
if (filp->f_flags & O_NONBLOCK) {
130
err = -EAGAIN;
131
goto out_unlock;
132
}
133
} else {
134
len = data_avail;
135
if (len > size)
136
len = size;
137
138
data_avail -= len;
139
140
if (copy_to_user(buf + ret, rng_buffer + data_avail,
141
len)) {
142
err = -EFAULT;
143
goto out_unlock;
144
}
145
146
size -= len;
147
ret += len;
148
}
149
150
mutex_unlock(&rng_mutex);
151
152
if (need_resched())
153
schedule_timeout_interruptible(1);
154
155
if (signal_pending(current)) {
156
err = -ERESTARTSYS;
157
goto out;
158
}
159
}
160
out:
161
return ret ? : err;
162
out_unlock:
163
mutex_unlock(&rng_mutex);
164
goto out;
165
}
166
167
168
static const struct file_operations rng_chrdev_ops = {
169
.owner = THIS_MODULE,
170
.open = rng_dev_open,
171
.read = rng_dev_read,
172
.llseek = noop_llseek,
173
};
174
175
static struct miscdevice rng_miscdev = {
176
.minor = RNG_MISCDEV_MINOR,
177
.name = RNG_MODULE_NAME,
178
.nodename = "hwrng",
179
.fops = &rng_chrdev_ops,
180
};
181
182
183
static ssize_t hwrng_attr_current_store(struct device *dev,
184
struct device_attribute *attr,
185
const char *buf, size_t len)
186
{
187
int err;
188
struct hwrng *rng;
189
190
err = mutex_lock_interruptible(&rng_mutex);
191
if (err)
192
return -ERESTARTSYS;
193
err = -ENODEV;
194
list_for_each_entry(rng, &rng_list, list) {
195
if (strcmp(rng->name, buf) == 0) {
196
if (rng == current_rng) {
197
err = 0;
198
break;
199
}
200
err = hwrng_init(rng);
201
if (err)
202
break;
203
hwrng_cleanup(current_rng);
204
current_rng = rng;
205
err = 0;
206
break;
207
}
208
}
209
mutex_unlock(&rng_mutex);
210
211
return err ? : len;
212
}
213
214
static ssize_t hwrng_attr_current_show(struct device *dev,
215
struct device_attribute *attr,
216
char *buf)
217
{
218
int err;
219
ssize_t ret;
220
const char *name = "none";
221
222
err = mutex_lock_interruptible(&rng_mutex);
223
if (err)
224
return -ERESTARTSYS;
225
if (current_rng)
226
name = current_rng->name;
227
ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
228
mutex_unlock(&rng_mutex);
229
230
return ret;
231
}
232
233
static ssize_t hwrng_attr_available_show(struct device *dev,
234
struct device_attribute *attr,
235
char *buf)
236
{
237
int err;
238
ssize_t ret = 0;
239
struct hwrng *rng;
240
241
err = mutex_lock_interruptible(&rng_mutex);
242
if (err)
243
return -ERESTARTSYS;
244
buf[0] = '\0';
245
list_for_each_entry(rng, &rng_list, list) {
246
strncat(buf, rng->name, PAGE_SIZE - ret - 1);
247
ret += strlen(rng->name);
248
strncat(buf, " ", PAGE_SIZE - ret - 1);
249
ret++;
250
}
251
strncat(buf, "\n", PAGE_SIZE - ret - 1);
252
ret++;
253
mutex_unlock(&rng_mutex);
254
255
return ret;
256
}
257
258
static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
259
hwrng_attr_current_show,
260
hwrng_attr_current_store);
261
static DEVICE_ATTR(rng_available, S_IRUGO,
262
hwrng_attr_available_show,
263
NULL);
264
265
266
static void unregister_miscdev(void)
267
{
268
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
269
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
270
misc_deregister(&rng_miscdev);
271
}
272
273
static int register_miscdev(void)
274
{
275
int err;
276
277
err = misc_register(&rng_miscdev);
278
if (err)
279
goto out;
280
err = device_create_file(rng_miscdev.this_device,
281
&dev_attr_rng_current);
282
if (err)
283
goto err_misc_dereg;
284
err = device_create_file(rng_miscdev.this_device,
285
&dev_attr_rng_available);
286
if (err)
287
goto err_remove_current;
288
out:
289
return err;
290
291
err_remove_current:
292
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
293
err_misc_dereg:
294
misc_deregister(&rng_miscdev);
295
goto out;
296
}
297
298
int hwrng_register(struct hwrng *rng)
299
{
300
int must_register_misc;
301
int err = -EINVAL;
302
struct hwrng *old_rng, *tmp;
303
304
if (rng->name == NULL ||
305
(rng->data_read == NULL && rng->read == NULL))
306
goto out;
307
308
mutex_lock(&rng_mutex);
309
310
/* Must not register two RNGs with the same name. */
311
err = -EEXIST;
312
list_for_each_entry(tmp, &rng_list, list) {
313
if (strcmp(tmp->name, rng->name) == 0)
314
goto out_unlock;
315
}
316
317
must_register_misc = (current_rng == NULL);
318
old_rng = current_rng;
319
if (!old_rng) {
320
err = hwrng_init(rng);
321
if (err)
322
goto out_unlock;
323
current_rng = rng;
324
}
325
err = 0;
326
if (must_register_misc) {
327
err = register_miscdev();
328
if (err) {
329
if (!old_rng) {
330
hwrng_cleanup(rng);
331
current_rng = NULL;
332
}
333
goto out_unlock;
334
}
335
}
336
INIT_LIST_HEAD(&rng->list);
337
list_add_tail(&rng->list, &rng_list);
338
out_unlock:
339
mutex_unlock(&rng_mutex);
340
out:
341
return err;
342
}
343
EXPORT_SYMBOL_GPL(hwrng_register);
344
345
void hwrng_unregister(struct hwrng *rng)
346
{
347
int err;
348
349
mutex_lock(&rng_mutex);
350
351
list_del(&rng->list);
352
if (current_rng == rng) {
353
hwrng_cleanup(rng);
354
if (list_empty(&rng_list)) {
355
current_rng = NULL;
356
} else {
357
current_rng = list_entry(rng_list.prev, struct hwrng, list);
358
err = hwrng_init(current_rng);
359
if (err)
360
current_rng = NULL;
361
}
362
}
363
if (list_empty(&rng_list))
364
unregister_miscdev();
365
366
mutex_unlock(&rng_mutex);
367
}
368
EXPORT_SYMBOL_GPL(hwrng_unregister);
369
370
371
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
372
MODULE_LICENSE("GPL");
373
374