diff options
| -rw-r--r-- | drivers/char/hw_random/core.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 334601cc81cf..48b3c812b9ec 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
| 39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
| 40 | #include <linux/miscdevice.h> | 40 | #include <linux/miscdevice.h> |
| 41 | #include <linux/kthread.h> | ||
| 41 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
| 42 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
| 43 | #include <linux/random.h> | 44 | #include <linux/random.h> |
| @@ -50,10 +51,18 @@ | |||
| 50 | 51 | ||
| 51 | 52 | ||
| 52 | static struct hwrng *current_rng; | 53 | static struct hwrng *current_rng; |
| 54 | static struct task_struct *hwrng_fill; | ||
| 53 | static LIST_HEAD(rng_list); | 55 | static LIST_HEAD(rng_list); |
| 54 | static DEFINE_MUTEX(rng_mutex); | 56 | static DEFINE_MUTEX(rng_mutex); |
| 55 | static int data_avail; | 57 | static int data_avail; |
| 56 | static u8 *rng_buffer; | 58 | static u8 *rng_buffer, *rng_fillbuf; |
| 59 | static unsigned short current_quality = 700; /* an arbitrary 70% */ | ||
| 60 | |||
| 61 | module_param(current_quality, ushort, 0644); | ||
| 62 | MODULE_PARM_DESC(current_quality, | ||
| 63 | "current hwrng entropy estimation per mill"); | ||
| 64 | |||
| 65 | static void start_khwrngd(void); | ||
| 57 | 66 | ||
| 58 | static size_t rng_buffer_size(void) | 67 | static size_t rng_buffer_size(void) |
| 59 | { | 68 | { |
| @@ -62,9 +71,18 @@ static size_t rng_buffer_size(void) | |||
| 62 | 71 | ||
| 63 | static inline int hwrng_init(struct hwrng *rng) | 72 | static inline int hwrng_init(struct hwrng *rng) |
| 64 | { | 73 | { |
| 65 | if (!rng->init) | 74 | int err; |
| 66 | return 0; | 75 | |
| 67 | return rng->init(rng); | 76 | if (rng->init) { |
| 77 | err = rng->init(rng); | ||
| 78 | if (err) | ||
| 79 | return err; | ||
| 80 | } | ||
| 81 | |||
| 82 | if (current_quality > 0 && !hwrng_fill) | ||
| 83 | start_khwrngd(); | ||
| 84 | |||
| 85 | return 0; | ||
| 68 | } | 86 | } |
| 69 | 87 | ||
| 70 | static inline void hwrng_cleanup(struct hwrng *rng) | 88 | static inline void hwrng_cleanup(struct hwrng *rng) |
| @@ -300,6 +318,36 @@ err_misc_dereg: | |||
| 300 | goto out; | 318 | goto out; |
| 301 | } | 319 | } |
| 302 | 320 | ||
| 321 | static int hwrng_fillfn(void *unused) | ||
| 322 | { | ||
| 323 | long rc; | ||
| 324 | |||
| 325 | while (!kthread_should_stop()) { | ||
| 326 | if (!current_rng) | ||
| 327 | break; | ||
| 328 | rc = rng_get_data(current_rng, rng_fillbuf, | ||
| 329 | rng_buffer_size(), 1); | ||
| 330 | if (rc <= 0) { | ||
| 331 | pr_warn("hwrng: no data available\n"); | ||
| 332 | msleep_interruptible(10000); | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | add_hwgenerator_randomness((void *)rng_fillbuf, rc, | ||
| 336 | (rc*current_quality)>>10); | ||
| 337 | } | ||
| 338 | hwrng_fill = 0; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static void start_khwrngd(void) | ||
| 343 | { | ||
| 344 | hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); | ||
| 345 | if (hwrng_fill == ERR_PTR(-ENOMEM)) { | ||
| 346 | pr_err("hwrng_fill thread creation failed"); | ||
| 347 | hwrng_fill = NULL; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 303 | int hwrng_register(struct hwrng *rng) | 351 | int hwrng_register(struct hwrng *rng) |
| 304 | { | 352 | { |
| 305 | int err = -EINVAL; | 353 | int err = -EINVAL; |
| @@ -320,6 +368,13 @@ int hwrng_register(struct hwrng *rng) | |||
| 320 | if (!rng_buffer) | 368 | if (!rng_buffer) |
| 321 | goto out_unlock; | 369 | goto out_unlock; |
| 322 | } | 370 | } |
| 371 | if (!rng_fillbuf) { | ||
| 372 | rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL); | ||
| 373 | if (!rng_fillbuf) { | ||
| 374 | kfree(rng_buffer); | ||
| 375 | goto out_unlock; | ||
| 376 | } | ||
| 377 | } | ||
| 323 | 378 | ||
| 324 | /* Must not register two RNGs with the same name. */ | 379 | /* Must not register two RNGs with the same name. */ |
| 325 | err = -EEXIST; | 380 | err = -EEXIST; |
| @@ -375,8 +430,11 @@ void hwrng_unregister(struct hwrng *rng) | |||
| 375 | current_rng = NULL; | 430 | current_rng = NULL; |
| 376 | } | 431 | } |
| 377 | } | 432 | } |
| 378 | if (list_empty(&rng_list)) | 433 | if (list_empty(&rng_list)) { |
| 379 | unregister_miscdev(); | 434 | unregister_miscdev(); |
| 435 | if (hwrng_fill) | ||
| 436 | kthread_stop(hwrng_fill); | ||
| 437 | } | ||
| 380 | 438 | ||
| 381 | mutex_unlock(&rng_mutex); | 439 | mutex_unlock(&rng_mutex); |
| 382 | } | 440 | } |
| @@ -387,6 +445,7 @@ static void __exit hwrng_exit(void) | |||
| 387 | mutex_lock(&rng_mutex); | 445 | mutex_lock(&rng_mutex); |
| 388 | BUG_ON(current_rng); | 446 | BUG_ON(current_rng); |
| 389 | kfree(rng_buffer); | 447 | kfree(rng_buffer); |
| 448 | kfree(rng_fillbuf); | ||
| 390 | mutex_unlock(&rng_mutex); | 449 | mutex_unlock(&rng_mutex); |
| 391 | } | 450 | } |
| 392 | 451 | ||
