Commit | Line | Data |
---|---|---|
844dd05f | 1 | /* |
dd801483 CL |
2 | * hw_random/core.c: HWRNG core API |
3 | * | |
4 | * Copyright 2006 Michael Buesch <m@bues.ch> | |
5 | * Copyright 2005 (c) MontaVista Software, Inc. | |
6 | * | |
4f4cfa6c | 7 | * Please read Documentation/admin-guide/hw_random.rst for details on use. |
dd801483 CL |
8 | * |
9 | * This software may be used and distributed according to the terms | |
10 | * of the GNU General Public License, incorporated herein by reference. | |
844dd05f MB |
11 | */ |
12 | ||
affdec58 | 13 | #include <linux/delay.h> |
844dd05f | 14 | #include <linux/device.h> |
affdec58 CL |
15 | #include <linux/err.h> |
16 | #include <linux/fs.h> | |
844dd05f | 17 | #include <linux/hw_random.h> |
844dd05f | 18 | #include <linux/kernel.h> |
be4000bc | 19 | #include <linux/kthread.h> |
174cd4b1 | 20 | #include <linux/sched/signal.h> |
affdec58 CL |
21 | #include <linux/miscdevice.h> |
22 | #include <linux/module.h> | |
d9e79726 | 23 | #include <linux/random.h> |
affdec58 CL |
24 | #include <linux/sched.h> |
25 | #include <linux/slab.h> | |
7c0f6ba6 | 26 | #include <linux/uaccess.h> |
844dd05f | 27 | |
844dd05f | 28 | #define RNG_MODULE_NAME "hw_random" |
844dd05f MB |
29 | |
30 | static struct hwrng *current_rng; | |
10a515dd HF |
31 | /* the current rng has been explicitly chosen by user via sysfs */ |
32 | static int cur_rng_set_by_user; | |
be4000bc | 33 | static struct task_struct *hwrng_fill; |
c90e4539 | 34 | /* list of registered rngs */ |
844dd05f | 35 | static LIST_HEAD(rng_list); |
9372b35e | 36 | /* Protects rng_list and current_rng */ |
844dd05f | 37 | static DEFINE_MUTEX(rng_mutex); |
9372b35e RR |
38 | /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ |
39 | static DEFINE_MUTEX(reading_mutex); | |
9996508b | 40 | static int data_avail; |
be4000bc | 41 | static u8 *rng_buffer, *rng_fillbuf; |
0f734e6e TD |
42 | static unsigned short current_quality; |
43 | static unsigned short default_quality; /* = 0; default to "off" */ | |
be4000bc TD |
44 | |
45 | module_param(current_quality, ushort, 0644); | |
46 | MODULE_PARM_DESC(current_quality, | |
f0fb6953 | 47 | "current hwrng entropy estimation per 1024 bits of input -- obsolete"); |
0f734e6e TD |
48 | module_param(default_quality, ushort, 0644); |
49 | MODULE_PARM_DESC(default_quality, | |
fae29f13 | 50 | "default entropy content of hwrng per 1024 bits of input"); |
be4000bc | 51 | |
ff77c150 | 52 | static void drop_current_rng(void); |
90ac41bd | 53 | static int hwrng_init(struct hwrng *rng); |
f0fb6953 | 54 | static void hwrng_manage_rngd(struct hwrng *rng); |
f7f154f1 | 55 | |
d3cc7996 AS |
56 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, |
57 | int wait); | |
58 | ||
f7f154f1 RR |
59 | static size_t rng_buffer_size(void) |
60 | { | |
61 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; | |
62 | } | |
844dd05f | 63 | |
d3cc7996 AS |
64 | static void add_early_randomness(struct hwrng *rng) |
65 | { | |
d3cc7996 AS |
66 | int bytes_read; |
67 | ||
9372b35e | 68 | mutex_lock(&reading_mutex); |
c05ac449 | 69 | bytes_read = rng_get_data(rng, rng_fillbuf, 32, 0); |
9372b35e | 70 | mutex_unlock(&reading_mutex); |
d3cc7996 | 71 | if (bytes_read > 0) |
c05ac449 | 72 | add_device_randomness(rng_fillbuf, bytes_read); |
d3cc7996 AS |
73 | } |
74 | ||
3a2c0ba5 RR |
75 | static inline void cleanup_rng(struct kref *kref) |
76 | { | |
77 | struct hwrng *rng = container_of(kref, struct hwrng, ref); | |
78 | ||
79 | if (rng->cleanup) | |
80 | rng->cleanup(rng); | |
a027f30d | 81 | |
77584ee5 | 82 | complete(&rng->cleanup_done); |
3a2c0ba5 RR |
83 | } |
84 | ||
90ac41bd | 85 | static int set_current_rng(struct hwrng *rng) |
3a2c0ba5 | 86 | { |
90ac41bd HX |
87 | int err; |
88 | ||
3a2c0ba5 | 89 | BUG_ON(!mutex_is_locked(&rng_mutex)); |
90ac41bd HX |
90 | |
91 | err = hwrng_init(rng); | |
92 | if (err) | |
93 | return err; | |
94 | ||
ff77c150 | 95 | drop_current_rng(); |
3a2c0ba5 | 96 | current_rng = rng; |
90ac41bd HX |
97 | |
98 | return 0; | |
3a2c0ba5 RR |
99 | } |
100 | ||
101 | static void drop_current_rng(void) | |
102 | { | |
103 | BUG_ON(!mutex_is_locked(&rng_mutex)); | |
104 | if (!current_rng) | |
105 | return; | |
106 | ||
107 | /* decrease last reference for triggering the cleanup */ | |
108 | kref_put(¤t_rng->ref, cleanup_rng); | |
109 | current_rng = NULL; | |
110 | } | |
111 | ||
112 | /* Returns ERR_PTR(), NULL or refcounted hwrng */ | |
daae28de LV |
113 | static struct hwrng *get_current_rng_nolock(void) |
114 | { | |
115 | if (current_rng) | |
116 | kref_get(¤t_rng->ref); | |
117 | ||
118 | return current_rng; | |
119 | } | |
120 | ||
3a2c0ba5 RR |
121 | static struct hwrng *get_current_rng(void) |
122 | { | |
123 | struct hwrng *rng; | |
124 | ||
125 | if (mutex_lock_interruptible(&rng_mutex)) | |
126 | return ERR_PTR(-ERESTARTSYS); | |
127 | ||
daae28de | 128 | rng = get_current_rng_nolock(); |
3a2c0ba5 RR |
129 | |
130 | mutex_unlock(&rng_mutex); | |
131 | return rng; | |
132 | } | |
133 | ||
134 | static void put_rng(struct hwrng *rng) | |
135 | { | |
136 | /* | |
137 | * Hold rng_mutex here so we serialize in case they set_current_rng | |
138 | * on rng again immediately. | |
139 | */ | |
140 | mutex_lock(&rng_mutex); | |
141 | if (rng) | |
142 | kref_put(&rng->ref, cleanup_rng); | |
143 | mutex_unlock(&rng_mutex); | |
144 | } | |
145 | ||
90ac41bd | 146 | static int hwrng_init(struct hwrng *rng) |
844dd05f | 147 | { |
15b66cd5 HX |
148 | if (kref_get_unless_zero(&rng->ref)) |
149 | goto skip_init; | |
150 | ||
d3cc7996 AS |
151 | if (rng->init) { |
152 | int ret; | |
153 | ||
154 | ret = rng->init(rng); | |
155 | if (ret) | |
156 | return ret; | |
157 | } | |
15b66cd5 HX |
158 | |
159 | kref_init(&rng->ref); | |
160 | reinit_completion(&rng->cleanup_done); | |
161 | ||
162 | skip_init: | |
f0fb6953 DB |
163 | if (!rng->quality) |
164 | rng->quality = default_quality; | |
165 | if (rng->quality > 1024) | |
166 | rng->quality = 1024; | |
167 | current_quality = rng->quality; /* obsolete */ | |
0f734e6e | 168 | |
f0fb6953 | 169 | hwrng_manage_rngd(rng); |
be4000bc | 170 | |
d3cc7996 | 171 | return 0; |
844dd05f MB |
172 | } |
173 | ||
844dd05f MB |
174 | static int rng_dev_open(struct inode *inode, struct file *filp) |
175 | { | |
176 | /* enforce read-only access to this chrdev */ | |
177 | if ((filp->f_mode & FMODE_READ) == 0) | |
178 | return -EINVAL; | |
179 | if (filp->f_mode & FMODE_WRITE) | |
180 | return -EINVAL; | |
181 | return 0; | |
182 | } | |
183 | ||
9996508b IM |
184 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, |
185 | int wait) { | |
186 | int present; | |
187 | ||
9372b35e | 188 | BUG_ON(!mutex_is_locked(&reading_mutex)); |
9996508b IM |
189 | if (rng->read) |
190 | return rng->read(rng, (void *)buffer, size, wait); | |
191 | ||
192 | if (rng->data_present) | |
193 | present = rng->data_present(rng, wait); | |
194 | else | |
195 | present = 1; | |
196 | ||
197 | if (present) | |
198 | return rng->data_read(rng, (u32 *)buffer); | |
199 | ||
200 | return 0; | |
201 | } | |
202 | ||
844dd05f MB |
203 | static ssize_t rng_dev_read(struct file *filp, char __user *buf, |
204 | size_t size, loff_t *offp) | |
205 | { | |
844dd05f | 206 | ssize_t ret = 0; |
984e976f | 207 | int err = 0; |
9996508b | 208 | int bytes_read, len; |
3a2c0ba5 | 209 | struct hwrng *rng; |
844dd05f MB |
210 | |
211 | while (size) { | |
3a2c0ba5 RR |
212 | rng = get_current_rng(); |
213 | if (IS_ERR(rng)) { | |
214 | err = PTR_ERR(rng); | |
844dd05f | 215 | goto out; |
9996508b | 216 | } |
3a2c0ba5 | 217 | if (!rng) { |
844dd05f | 218 | err = -ENODEV; |
3a2c0ba5 | 219 | goto out; |
844dd05f | 220 | } |
984e976f | 221 | |
1ab87298 JS |
222 | if (mutex_lock_interruptible(&reading_mutex)) { |
223 | err = -ERESTARTSYS; | |
224 | goto out_put; | |
225 | } | |
9996508b | 226 | if (!data_avail) { |
3a2c0ba5 | 227 | bytes_read = rng_get_data(rng, rng_buffer, |
f7f154f1 | 228 | rng_buffer_size(), |
9996508b IM |
229 | !(filp->f_flags & O_NONBLOCK)); |
230 | if (bytes_read < 0) { | |
231 | err = bytes_read; | |
9372b35e | 232 | goto out_unlock_reading; |
9996508b IM |
233 | } |
234 | data_avail = bytes_read; | |
893f1128 | 235 | } |
844dd05f | 236 | |
9996508b IM |
237 | if (!data_avail) { |
238 | if (filp->f_flags & O_NONBLOCK) { | |
239 | err = -EAGAIN; | |
9372b35e | 240 | goto out_unlock_reading; |
9996508b IM |
241 | } |
242 | } else { | |
243 | len = data_avail; | |
244 | if (len > size) | |
245 | len = size; | |
246 | ||
247 | data_avail -= len; | |
248 | ||
249 | if (copy_to_user(buf + ret, rng_buffer + data_avail, | |
250 | len)) { | |
251 | err = -EFAULT; | |
9372b35e | 252 | goto out_unlock_reading; |
9996508b IM |
253 | } |
254 | ||
255 | size -= len; | |
256 | ret += len; | |
844dd05f MB |
257 | } |
258 | ||
9372b35e | 259 | mutex_unlock(&reading_mutex); |
3a2c0ba5 | 260 | put_rng(rng); |
9996508b | 261 | |
844dd05f MB |
262 | if (need_resched()) |
263 | schedule_timeout_interruptible(1); | |
9996508b IM |
264 | |
265 | if (signal_pending(current)) { | |
266 | err = -ERESTARTSYS; | |
844dd05f | 267 | goto out; |
9996508b | 268 | } |
844dd05f MB |
269 | } |
270 | out: | |
271 | return ret ? : err; | |
3a2c0ba5 | 272 | |
9372b35e RR |
273 | out_unlock_reading: |
274 | mutex_unlock(&reading_mutex); | |
1ab87298 | 275 | out_put: |
3a2c0ba5 RR |
276 | put_rng(rng); |
277 | goto out; | |
844dd05f MB |
278 | } |
279 | ||
62322d25 | 280 | static const struct file_operations rng_chrdev_ops = { |
844dd05f MB |
281 | .owner = THIS_MODULE, |
282 | .open = rng_dev_open, | |
283 | .read = rng_dev_read, | |
6038f373 | 284 | .llseek = noop_llseek, |
844dd05f MB |
285 | }; |
286 | ||
0daa7a0a TI |
287 | static const struct attribute_group *rng_dev_groups[]; |
288 | ||
844dd05f | 289 | static struct miscdevice rng_miscdev = { |
fd50d71f | 290 | .minor = HWRNG_MINOR, |
844dd05f | 291 | .name = RNG_MODULE_NAME, |
e454cea2 | 292 | .nodename = "hwrng", |
844dd05f | 293 | .fops = &rng_chrdev_ops, |
0daa7a0a | 294 | .groups = rng_dev_groups, |
844dd05f MB |
295 | }; |
296 | ||
142a27f0 PM |
297 | static int enable_best_rng(void) |
298 | { | |
c90e4539 | 299 | struct hwrng *rng, *new_rng = NULL; |
142a27f0 PM |
300 | int ret = -ENODEV; |
301 | ||
302 | BUG_ON(!mutex_is_locked(&rng_mutex)); | |
303 | ||
c90e4539 DB |
304 | /* no rng to use? */ |
305 | if (list_empty(&rng_list)) { | |
0e4b5294 GH |
306 | drop_current_rng(); |
307 | cur_rng_set_by_user = 0; | |
c90e4539 DB |
308 | return 0; |
309 | } | |
310 | ||
311 | /* use the rng which offers the best quality */ | |
312 | list_for_each_entry(rng, &rng_list, list) { | |
313 | if (!new_rng || rng->quality > new_rng->quality) | |
314 | new_rng = rng; | |
142a27f0 PM |
315 | } |
316 | ||
c90e4539 DB |
317 | ret = ((new_rng == current_rng) ? 0 : set_current_rng(new_rng)); |
318 | if (!ret) | |
319 | cur_rng_set_by_user = 0; | |
320 | ||
142a27f0 PM |
321 | return ret; |
322 | } | |
323 | ||
98f481f2 Y |
324 | static ssize_t rng_current_store(struct device *dev, |
325 | struct device_attribute *attr, | |
326 | const char *buf, size_t len) | |
844dd05f | 327 | { |
cb028f16 | 328 | int err; |
daae28de | 329 | struct hwrng *rng, *old_rng, *new_rng; |
844dd05f MB |
330 | |
331 | err = mutex_lock_interruptible(&rng_mutex); | |
332 | if (err) | |
333 | return -ERESTARTSYS; | |
142a27f0 | 334 | |
daae28de | 335 | old_rng = current_rng; |
142a27f0 PM |
336 | if (sysfs_streq(buf, "")) { |
337 | err = enable_best_rng(); | |
338 | } else { | |
339 | list_for_each_entry(rng, &rng_list, list) { | |
340 | if (sysfs_streq(rng->name, buf)) { | |
90ac41bd | 341 | err = set_current_rng(rng); |
f41aa47c DB |
342 | if (!err) |
343 | cur_rng_set_by_user = 1; | |
142a27f0 PM |
344 | break; |
345 | } | |
844dd05f MB |
346 | } |
347 | } | |
daae28de | 348 | new_rng = get_current_rng_nolock(); |
844dd05f MB |
349 | mutex_unlock(&rng_mutex); |
350 | ||
daae28de LV |
351 | if (new_rng) { |
352 | if (new_rng != old_rng) | |
353 | add_early_randomness(new_rng); | |
354 | put_rng(new_rng); | |
355 | } | |
356 | ||
844dd05f MB |
357 | return err ? : len; |
358 | } | |
359 | ||
98f481f2 Y |
360 | static ssize_t rng_current_show(struct device *dev, |
361 | struct device_attribute *attr, | |
362 | char *buf) | |
844dd05f | 363 | { |
844dd05f | 364 | ssize_t ret; |
3a2c0ba5 | 365 | struct hwrng *rng; |
844dd05f | 366 | |
3a2c0ba5 RR |
367 | rng = get_current_rng(); |
368 | if (IS_ERR(rng)) | |
369 | return PTR_ERR(rng); | |
370 | ||
371 | ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none"); | |
372 | put_rng(rng); | |
844dd05f MB |
373 | |
374 | return ret; | |
375 | } | |
376 | ||
98f481f2 Y |
377 | static ssize_t rng_available_show(struct device *dev, |
378 | struct device_attribute *attr, | |
379 | char *buf) | |
844dd05f MB |
380 | { |
381 | int err; | |
844dd05f MB |
382 | struct hwrng *rng; |
383 | ||
384 | err = mutex_lock_interruptible(&rng_mutex); | |
385 | if (err) | |
386 | return -ERESTARTSYS; | |
387 | buf[0] = '\0'; | |
388 | list_for_each_entry(rng, &rng_list, list) { | |
61daf055 RS |
389 | strlcat(buf, rng->name, PAGE_SIZE); |
390 | strlcat(buf, " ", PAGE_SIZE); | |
844dd05f | 391 | } |
61daf055 | 392 | strlcat(buf, "\n", PAGE_SIZE); |
844dd05f MB |
393 | mutex_unlock(&rng_mutex); |
394 | ||
61daf055 | 395 | return strlen(buf); |
844dd05f MB |
396 | } |
397 | ||
98f481f2 Y |
398 | static ssize_t rng_selected_show(struct device *dev, |
399 | struct device_attribute *attr, | |
400 | char *buf) | |
10a515dd | 401 | { |
91253022 | 402 | return sysfs_emit(buf, "%d\n", cur_rng_set_by_user); |
10a515dd HF |
403 | } |
404 | ||
98f481f2 Y |
405 | static DEVICE_ATTR_RW(rng_current); |
406 | static DEVICE_ATTR_RO(rng_available); | |
407 | static DEVICE_ATTR_RO(rng_selected); | |
844dd05f | 408 | |
0daa7a0a TI |
409 | static struct attribute *rng_dev_attrs[] = { |
410 | &dev_attr_rng_current.attr, | |
411 | &dev_attr_rng_available.attr, | |
10a515dd | 412 | &dev_attr_rng_selected.attr, |
0daa7a0a TI |
413 | NULL |
414 | }; | |
415 | ||
416 | ATTRIBUTE_GROUPS(rng_dev); | |
844dd05f | 417 | |
ac3a497f | 418 | static void __exit unregister_miscdev(void) |
844dd05f | 419 | { |
b844eba2 | 420 | misc_deregister(&rng_miscdev); |
844dd05f MB |
421 | } |
422 | ||
ac3a497f | 423 | static int __init register_miscdev(void) |
844dd05f | 424 | { |
0daa7a0a | 425 | return misc_register(&rng_miscdev); |
844dd05f MB |
426 | } |
427 | ||
be4000bc TD |
428 | static int hwrng_fillfn(void *unused) |
429 | { | |
a43bed82 | 430 | size_t entropy, entropy_credit = 0; /* in 1/1024 of a bit */ |
be4000bc TD |
431 | long rc; |
432 | ||
08e97aec | 433 | while (!kthread_should_stop()) { |
f0fb6953 | 434 | unsigned short quality; |
3a2c0ba5 RR |
435 | struct hwrng *rng; |
436 | ||
437 | rng = get_current_rng(); | |
438 | if (IS_ERR(rng) || !rng) | |
be4000bc | 439 | break; |
9372b35e | 440 | mutex_lock(&reading_mutex); |
3a2c0ba5 | 441 | rc = rng_get_data(rng, rng_fillbuf, |
be4000bc | 442 | rng_buffer_size(), 1); |
f0fb6953 DB |
443 | if (current_quality != rng->quality) |
444 | rng->quality = current_quality; /* obsolete */ | |
445 | quality = rng->quality; | |
9372b35e | 446 | mutex_unlock(&reading_mutex); |
3a2c0ba5 | 447 | put_rng(rng); |
f0fb6953 DB |
448 | |
449 | if (!quality) | |
450 | break; | |
451 | ||
be4000bc TD |
452 | if (rc <= 0) { |
453 | pr_warn("hwrng: no data available\n"); | |
454 | msleep_interruptible(10000); | |
455 | continue; | |
456 | } | |
a43bed82 DB |
457 | |
458 | /* If we cannot credit at least one bit of entropy, | |
459 | * keep track of the remainder for the next iteration | |
460 | */ | |
f0fb6953 | 461 | entropy = rc * quality * 8 + entropy_credit; |
a43bed82 DB |
462 | if ((entropy >> 10) == 0) |
463 | entropy_credit = entropy; | |
464 | ||
9372b35e | 465 | /* Outside lock, sure, but y'know: randomness. */ |
be4000bc | 466 | add_hwgenerator_randomness((void *)rng_fillbuf, rc, |
a43bed82 | 467 | entropy >> 10); |
be4000bc | 468 | } |
9dda727d | 469 | hwrng_fill = NULL; |
be4000bc TD |
470 | return 0; |
471 | } | |
472 | ||
f0fb6953 | 473 | static void hwrng_manage_rngd(struct hwrng *rng) |
be4000bc | 474 | { |
077bb7a1 DB |
475 | if (WARN_ON(!mutex_is_locked(&rng_mutex))) |
476 | return; | |
477 | ||
f0fb6953 | 478 | if (rng->quality == 0 && hwrng_fill) |
077bb7a1 | 479 | kthread_stop(hwrng_fill); |
f0fb6953 | 480 | if (rng->quality > 0 && !hwrng_fill) { |
077bb7a1 DB |
481 | hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); |
482 | if (IS_ERR(hwrng_fill)) { | |
483 | pr_err("hwrng_fill thread creation failed\n"); | |
484 | hwrng_fill = NULL; | |
485 | } | |
be4000bc TD |
486 | } |
487 | } | |
488 | ||
844dd05f MB |
489 | int hwrng_register(struct hwrng *rng) |
490 | { | |
844dd05f | 491 | int err = -EINVAL; |
28443671 | 492 | struct hwrng *tmp; |
28443671 | 493 | bool is_new_current = false; |
844dd05f | 494 | |
2a971e3b | 495 | if (!rng->name || (!rng->data_read && !rng->read)) |
844dd05f MB |
496 | goto out; |
497 | ||
498 | mutex_lock(&rng_mutex); | |
daae28de | 499 | |
844dd05f MB |
500 | /* Must not register two RNGs with the same name. */ |
501 | err = -EEXIST; | |
502 | list_for_each_entry(tmp, &rng_list, list) { | |
503 | if (strcmp(tmp->name, rng->name) == 0) | |
504 | goto out_unlock; | |
505 | } | |
c90e4539 | 506 | list_add_tail(&rng->list, &rng_list); |
844dd05f | 507 | |
15b66cd5 HX |
508 | init_completion(&rng->cleanup_done); |
509 | complete(&rng->cleanup_done); | |
510 | ||
28443671 LV |
511 | if (!current_rng || |
512 | (!cur_rng_set_by_user && rng->quality > current_rng->quality)) { | |
2bbb6983 HF |
513 | /* |
514 | * Set new rng as current as the new rng source | |
10a515dd HF |
515 | * provides better entropy quality and was not |
516 | * chosen by userspace. | |
2bbb6983 | 517 | */ |
90ac41bd | 518 | err = set_current_rng(rng); |
844dd05f MB |
519 | if (err) |
520 | goto out_unlock; | |
28443671 LV |
521 | /* to use current_rng in add_early_randomness() we need |
522 | * to take a ref | |
523 | */ | |
524 | is_new_current = true; | |
525 | kref_get(&rng->ref); | |
844dd05f | 526 | } |
daae28de | 527 | mutex_unlock(&rng_mutex); |
28443671 | 528 | if (is_new_current || !rng->init) { |
d3cc7996 AS |
529 | /* |
530 | * Use a new device's input to add some randomness to | |
531 | * the system. If this rng device isn't going to be | |
532 | * used right away, its init function hasn't been | |
daae28de LV |
533 | * called yet by set_current_rng(); so only use the |
534 | * randomness from devices that don't need an init callback | |
d3cc7996 AS |
535 | */ |
536 | add_early_randomness(rng); | |
537 | } | |
28443671 LV |
538 | if (is_new_current) |
539 | put_rng(rng); | |
540 | return 0; | |
844dd05f MB |
541 | out_unlock: |
542 | mutex_unlock(&rng_mutex); | |
543 | out: | |
544 | return err; | |
545 | } | |
546 | EXPORT_SYMBOL_GPL(hwrng_register); | |
547 | ||
b844eba2 | 548 | void hwrng_unregister(struct hwrng *rng) |
844dd05f | 549 | { |
daae28de | 550 | struct hwrng *old_rng, *new_rng; |
837bf7cc MB |
551 | int err; |
552 | ||
844dd05f MB |
553 | mutex_lock(&rng_mutex); |
554 | ||
daae28de | 555 | old_rng = current_rng; |
844dd05f | 556 | list_del(&rng->list); |
837bf7cc MB |
557 | if (current_rng == rng) { |
558 | err = enable_best_rng(); | |
559 | if (err) { | |
560 | drop_current_rng(); | |
561 | cur_rng_set_by_user = 0; | |
562 | } | |
563 | } | |
3a2c0ba5 | 564 | |
daae28de | 565 | new_rng = get_current_rng_nolock(); |
be4000bc | 566 | if (list_empty(&rng_list)) { |
1dacb395 | 567 | mutex_unlock(&rng_mutex); |
be4000bc TD |
568 | if (hwrng_fill) |
569 | kthread_stop(hwrng_fill); | |
1dacb395 AK |
570 | } else |
571 | mutex_unlock(&rng_mutex); | |
a027f30d | 572 | |
daae28de LV |
573 | if (new_rng) { |
574 | if (old_rng != new_rng) | |
575 | add_early_randomness(new_rng); | |
576 | put_rng(new_rng); | |
577 | } | |
578 | ||
77584ee5 | 579 | wait_for_completion(&rng->cleanup_done); |
844dd05f | 580 | } |
b844eba2 | 581 | EXPORT_SYMBOL_GPL(hwrng_unregister); |
844dd05f | 582 | |
4d9b519c DT |
583 | static void devm_hwrng_release(struct device *dev, void *res) |
584 | { | |
585 | hwrng_unregister(*(struct hwrng **)res); | |
586 | } | |
587 | ||
588 | static int devm_hwrng_match(struct device *dev, void *res, void *data) | |
589 | { | |
590 | struct hwrng **r = res; | |
591 | ||
592 | if (WARN_ON(!r || !*r)) | |
593 | return 0; | |
594 | ||
595 | return *r == data; | |
596 | } | |
597 | ||
598 | int devm_hwrng_register(struct device *dev, struct hwrng *rng) | |
599 | { | |
600 | struct hwrng **ptr; | |
601 | int error; | |
602 | ||
603 | ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL); | |
604 | if (!ptr) | |
605 | return -ENOMEM; | |
606 | ||
607 | error = hwrng_register(rng); | |
608 | if (error) { | |
609 | devres_free(ptr); | |
610 | return error; | |
611 | } | |
612 | ||
613 | *ptr = rng; | |
614 | devres_add(dev, ptr); | |
615 | return 0; | |
616 | } | |
617 | EXPORT_SYMBOL_GPL(devm_hwrng_register); | |
618 | ||
619 | void devm_hwrng_unregister(struct device *dev, struct hwrng *rng) | |
620 | { | |
621 | devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng); | |
622 | } | |
623 | EXPORT_SYMBOL_GPL(devm_hwrng_unregister); | |
624 | ||
ac3a497f HX |
625 | static int __init hwrng_modinit(void) |
626 | { | |
45645709 | 627 | int ret; |
58b022ac PM |
628 | |
629 | /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */ | |
630 | rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL); | |
631 | if (!rng_buffer) | |
632 | return -ENOMEM; | |
633 | ||
634 | rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL); | |
635 | if (!rng_fillbuf) { | |
636 | kfree(rng_buffer); | |
637 | return -ENOMEM; | |
638 | } | |
639 | ||
640 | ret = register_miscdev(); | |
641 | if (ret) { | |
642 | kfree(rng_fillbuf); | |
643 | kfree(rng_buffer); | |
644 | } | |
645 | ||
646 | return ret; | |
ac3a497f HX |
647 | } |
648 | ||
649 | static void __exit hwrng_modexit(void) | |
b7d44d94 ST |
650 | { |
651 | mutex_lock(&rng_mutex); | |
652 | BUG_ON(current_rng); | |
653 | kfree(rng_buffer); | |
be4000bc | 654 | kfree(rng_fillbuf); |
b7d44d94 | 655 | mutex_unlock(&rng_mutex); |
ac3a497f HX |
656 | |
657 | unregister_miscdev(); | |
b7d44d94 ST |
658 | } |
659 | ||
26a03981 | 660 | fs_initcall(hwrng_modinit); /* depends on misc_register() */ |
ac3a497f | 661 | module_exit(hwrng_modexit); |
844dd05f MB |
662 | |
663 | MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); | |
664 | MODULE_LICENSE("GPL"); |