1 | /* Copyright (C) 2005 - 2008 Jeff Dike <jdike@{linux.intel,addtoit}.com> */ |
2 | |
3 | /* Much of this ripped from drivers/char/hw_random.c, see there for other |
4 | * copyright. |
5 | * |
6 | * This software may be used and distributed according to the terms |
7 | * of the GNU General Public License, incorporated herein by reference. |
8 | */ |
9 | #include <linux/sched/signal.h> |
10 | #include <linux/module.h> |
11 | #include <linux/fs.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/miscdevice.h> |
14 | #include <linux/hw_random.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/uaccess.h> |
17 | #include <init.h> |
18 | #include <irq_kern.h> |
19 | #include <os.h> |
20 | |
21 | /* |
22 | * core module information |
23 | */ |
24 | #define RNG_MODULE_NAME "hw_random" |
25 | |
26 | /* Changed at init time, in the non-modular case, and at module load |
27 | * time, in the module case. Presumably, the module subsystem |
28 | * protects against a module being loaded twice at the same time. |
29 | */ |
30 | static int random_fd = -1; |
31 | static struct hwrng hwrng; |
32 | static DECLARE_COMPLETION(have_data); |
33 | |
34 | static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block) |
35 | { |
36 | int ret; |
37 | |
38 | for (;;) { |
39 | ret = os_read_file(random_fd, buf, max); |
40 | if (block && ret == -EAGAIN) { |
41 | add_sigio_fd(random_fd); |
42 | |
43 | ret = wait_for_completion_killable(x: &have_data); |
44 | |
45 | ignore_sigio_fd(random_fd); |
46 | deactivate_fd(random_fd, RANDOM_IRQ); |
47 | |
48 | if (ret < 0) |
49 | break; |
50 | } else { |
51 | break; |
52 | } |
53 | } |
54 | |
55 | return ret != -EAGAIN ? ret : 0; |
56 | } |
57 | |
58 | static irqreturn_t random_interrupt(int irq, void *data) |
59 | { |
60 | complete(&have_data); |
61 | |
62 | return IRQ_HANDLED; |
63 | } |
64 | |
65 | /* |
66 | * rng_init - initialize RNG module |
67 | */ |
68 | static int __init rng_init (void) |
69 | { |
70 | int err; |
71 | |
72 | err = os_open_file("/dev/random" , of_read(OPENFLAGS()), 0); |
73 | if (err < 0) |
74 | goto out; |
75 | |
76 | random_fd = err; |
77 | err = um_request_irq(RANDOM_IRQ, random_fd, IRQ_READ, random_interrupt, |
78 | 0, "random" , NULL); |
79 | if (err < 0) |
80 | goto err_out_cleanup_hw; |
81 | |
82 | sigio_broken(random_fd); |
83 | hwrng.name = RNG_MODULE_NAME; |
84 | hwrng.read = rng_dev_read; |
85 | |
86 | err = hwrng_register(rng: &hwrng); |
87 | if (err) { |
88 | pr_err(RNG_MODULE_NAME " registering failed (%d)\n" , err); |
89 | goto err_out_cleanup_hw; |
90 | } |
91 | out: |
92 | return err; |
93 | |
94 | err_out_cleanup_hw: |
95 | os_close_file(random_fd); |
96 | random_fd = -1; |
97 | goto out; |
98 | } |
99 | |
100 | /* |
101 | * rng_cleanup - shutdown RNG module |
102 | */ |
103 | |
104 | static void cleanup(void) |
105 | { |
106 | free_irq_by_fd(random_fd); |
107 | os_close_file(random_fd); |
108 | } |
109 | |
110 | static void __exit rng_cleanup(void) |
111 | { |
112 | hwrng_unregister(rng: &hwrng); |
113 | os_close_file(random_fd); |
114 | } |
115 | |
116 | module_init (rng_init); |
117 | module_exit (rng_cleanup); |
118 | __uml_exitcall(cleanup); |
119 | |
120 | MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver" ); |
121 | MODULE_LICENSE("GPL" ); |
122 | |