aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 18:55:13 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 18:55:13 -0500
commite069efb6bbf8f739a2e084183709b5eb76abf90d (patch)
tree0866058fa6e1b77d9defc6f45f39d1f851afe327 /drivers/char
parent324889b6bd2a89e0d69a2f9d133d6cf24579ab6c (diff)
parenteed89d0f9d3383851cec634565a6414fae70fe91 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: hwrng: core - Prevent too-small buffer sizes hwrng: virtio-rng - Convert to new API hwrng: core - Replace u32 in driver API with byte array crypto: ansi_cprng - Move FIPS functions under CONFIG_CRYPTO_FIPS crypto: testmgr - Add ghash algorithm test before provide to users crypto: ghash-clmulni-intel - Put proper .data section in place crypto: ghash-clmulni-intel - Use gas macro for PCLMULQDQ-NI and PSHUFB crypto: aesni-intel - Use gas macro for AES-NI instructions x86: Generate .byte code for some new instructions via gas macro crypto: ghash-intel - Fix irq_fpu_usable usage crypto: ghash-intel - Add PSHUFB macros crypto: ghash-intel - Hard-code pshufb crypto: ghash-intel - Fix building failure on x86_32 crypto: testmgr - Fix warning crypto: ansi_cprng - Fix test in get_prng_bytes crypto: hash - Remove cra_u.{digest,hash} crypto: api - Remove digest case from procfs show handler crypto: hash - Remove legacy hash/digest code crypto: ansi_cprng - Add FIPS wrapper crypto: ghash - Add PCLMULQDQ accelerated implementation
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/hw_random/core.c108
-rw-r--r--drivers/char/hw_random/virtio-rng.c78
2 files changed, 92 insertions, 94 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1573aebd54b5..8b7d56a0fe3a 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -52,7 +52,9 @@
52static struct hwrng *current_rng; 52static struct hwrng *current_rng;
53static LIST_HEAD(rng_list); 53static LIST_HEAD(rng_list);
54static DEFINE_MUTEX(rng_mutex); 54static DEFINE_MUTEX(rng_mutex);
55 55static int data_avail;
56static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES]
57 __cacheline_aligned;
56 58
57static inline int hwrng_init(struct hwrng *rng) 59static inline int hwrng_init(struct hwrng *rng)
58{ 60{
@@ -67,19 +69,6 @@ static inline void hwrng_cleanup(struct hwrng *rng)
67 rng->cleanup(rng); 69 rng->cleanup(rng);
68} 70}
69 71
70static inline int hwrng_data_present(struct hwrng *rng, int wait)
71{
72 if (!rng->data_present)
73 return 1;
74 return rng->data_present(rng, wait);
75}
76
77static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
78{
79 return rng->data_read(rng, data);
80}
81
82
83static int rng_dev_open(struct inode *inode, struct file *filp) 72static int rng_dev_open(struct inode *inode, struct file *filp)
84{ 73{
85 /* enforce read-only access to this chrdev */ 74 /* enforce read-only access to this chrdev */
@@ -91,54 +80,87 @@ static int rng_dev_open(struct inode *inode, struct file *filp)
91 return 0; 80 return 0;
92} 81}
93 82
83static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
84 int wait) {
85 int present;
86
87 if (rng->read)
88 return rng->read(rng, (void *)buffer, size, wait);
89
90 if (rng->data_present)
91 present = rng->data_present(rng, wait);
92 else
93 present = 1;
94
95 if (present)
96 return rng->data_read(rng, (u32 *)buffer);
97
98 return 0;
99}
100
94static ssize_t rng_dev_read(struct file *filp, char __user *buf, 101static ssize_t rng_dev_read(struct file *filp, char __user *buf,
95 size_t size, loff_t *offp) 102 size_t size, loff_t *offp)
96{ 103{
97 u32 data;
98 ssize_t ret = 0; 104 ssize_t ret = 0;
99 int err = 0; 105 int err = 0;
100 int bytes_read; 106 int bytes_read, len;
101 107
102 while (size) { 108 while (size) {
103 err = -ERESTARTSYS; 109 if (mutex_lock_interruptible(&rng_mutex)) {
104 if (mutex_lock_interruptible(&rng_mutex)) 110 err = -ERESTARTSYS;
105 goto out; 111 goto out;
112 }
113
106 if (!current_rng) { 114 if (!current_rng) {
107 mutex_unlock(&rng_mutex);
108 err = -ENODEV; 115 err = -ENODEV;
109 goto out; 116 goto out_unlock;
110 } 117 }
111 118
112 bytes_read = 0; 119 if (!data_avail) {
113 if (hwrng_data_present(current_rng, 120 bytes_read = rng_get_data(current_rng, rng_buffer,
114 !(filp->f_flags & O_NONBLOCK))) 121 sizeof(rng_buffer),
115 bytes_read = hwrng_data_read(current_rng, &data); 122 !(filp->f_flags & O_NONBLOCK));
116 mutex_unlock(&rng_mutex); 123 if (bytes_read < 0) {
117 124 err = bytes_read;
118 err = -EAGAIN; 125 goto out_unlock;
119 if (!bytes_read && (filp->f_flags & O_NONBLOCK)) 126 }
120 goto out; 127 data_avail = bytes_read;
121 if (bytes_read < 0) {
122 err = bytes_read;
123 goto out;
124 } 128 }
125 129
126 err = -EFAULT; 130 if (!data_avail) {
127 while (bytes_read && size) { 131 if (filp->f_flags & O_NONBLOCK) {
128 if (put_user((u8)data, buf++)) 132 err = -EAGAIN;
129 goto out; 133 goto out_unlock;
130 size--; 134 }
131 ret++; 135 } else {
132 bytes_read--; 136 len = data_avail;
133 data >>= 8; 137 if (len > size)
138 len = size;
139
140 data_avail -= len;
141
142 if (copy_to_user(buf + ret, rng_buffer + data_avail,
143 len)) {
144 err = -EFAULT;
145 goto out_unlock;
146 }
147
148 size -= len;
149 ret += len;
134 } 150 }
135 151
152 mutex_unlock(&rng_mutex);
153
136 if (need_resched()) 154 if (need_resched())
137 schedule_timeout_interruptible(1); 155 schedule_timeout_interruptible(1);
138 err = -ERESTARTSYS; 156
139 if (signal_pending(current)) 157 if (signal_pending(current)) {
158 err = -ERESTARTSYS;
140 goto out; 159 goto out;
160 }
141 } 161 }
162out_unlock:
163 mutex_unlock(&rng_mutex);
142out: 164out:
143 return ret ? : err; 165 return ret ? : err;
144} 166}
@@ -280,7 +302,7 @@ int hwrng_register(struct hwrng *rng)
280 struct hwrng *old_rng, *tmp; 302 struct hwrng *old_rng, *tmp;
281 303
282 if (rng->name == NULL || 304 if (rng->name == NULL ||
283 rng->data_read == NULL) 305 (rng->data_read == NULL && rng->read == NULL))
284 goto out; 306 goto out;
285 307
286 mutex_lock(&rng_mutex); 308 mutex_lock(&rng_mutex);
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 915157fcff98..bdaef8e94021 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -16,6 +16,7 @@
16 * along with this program; if not, write to the Free Software 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 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */ 18 */
19
19#include <linux/err.h> 20#include <linux/err.h>
20#include <linux/hw_random.h> 21#include <linux/hw_random.h>
21#include <linux/scatterlist.h> 22#include <linux/scatterlist.h>
@@ -23,78 +24,64 @@
23#include <linux/virtio.h> 24#include <linux/virtio.h>
24#include <linux/virtio_rng.h> 25#include <linux/virtio_rng.h>
25 26
26/* The host will fill any buffer we give it with sweet, sweet randomness. We
27 * give it 64 bytes at a time, and the hwrng framework takes it 4 bytes at a
28 * time. */
29#define RANDOM_DATA_SIZE 64
30
31static struct virtqueue *vq; 27static struct virtqueue *vq;
32static u32 *random_data; 28static unsigned int data_avail;
33static unsigned int data_left;
34static DECLARE_COMPLETION(have_data); 29static DECLARE_COMPLETION(have_data);
30static bool busy;
35 31
36static void random_recv_done(struct virtqueue *vq) 32static void random_recv_done(struct virtqueue *vq)
37{ 33{
38 unsigned int len;
39
40 /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ 34 /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
41 if (!vq->vq_ops->get_buf(vq, &len)) 35 if (!vq->vq_ops->get_buf(vq, &data_avail))
42 return; 36 return;
43 37
44 data_left += len;
45 complete(&have_data); 38 complete(&have_data);
46} 39}
47 40
48static void register_buffer(void) 41/* The host will fill any buffer we give it with sweet, sweet randomness. */
42static void register_buffer(u8 *buf, size_t size)
49{ 43{
50 struct scatterlist sg; 44 struct scatterlist sg;
51 45
52 sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left); 46 sg_init_one(&sg, buf, size);
47
53 /* There should always be room for one buffer. */ 48 /* There should always be room for one buffer. */
54 if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) < 0) 49 if (vq->vq_ops->add_buf(vq, &sg, 0, 1, buf) < 0)
55 BUG(); 50 BUG();
51
56 vq->vq_ops->kick(vq); 52 vq->vq_ops->kick(vq);
57} 53}
58 54
59/* At least we don't udelay() in a loop like some other drivers. */ 55static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
60static int virtio_data_present(struct hwrng *rng, int wait)
61{ 56{
62 if (data_left >= sizeof(u32))
63 return 1;
64 57
65again: 58 if (!busy) {
59 busy = true;
60 init_completion(&have_data);
61 register_buffer(buf, size);
62 }
63
66 if (!wait) 64 if (!wait)
67 return 0; 65 return 0;
68 66
69 wait_for_completion(&have_data); 67 wait_for_completion(&have_data);
70 68
71 /* Not enough? Re-register. */ 69 busy = false;
72 if (unlikely(data_left < sizeof(u32))) {
73 register_buffer();
74 goto again;
75 }
76 70
77 return 1; 71 return data_avail;
78} 72}
79 73
80/* virtio_data_present() must have succeeded before this is called. */ 74static void virtio_cleanup(struct hwrng *rng)
81static int virtio_data_read(struct hwrng *rng, u32 *data)
82{ 75{
83 BUG_ON(data_left < sizeof(u32)); 76 if (busy)
84 data_left -= sizeof(u32); 77 wait_for_completion(&have_data);
85 *data = random_data[data_left / 4];
86
87 if (data_left < sizeof(u32)) {
88 init_completion(&have_data);
89 register_buffer();
90 }
91 return sizeof(*data);
92} 78}
93 79
80
94static struct hwrng virtio_hwrng = { 81static struct hwrng virtio_hwrng = {
95 .name = "virtio", 82 .name = "virtio",
96 .data_present = virtio_data_present, 83 .cleanup = virtio_cleanup,
97 .data_read = virtio_data_read, 84 .read = virtio_read,
98}; 85};
99 86
100static int virtrng_probe(struct virtio_device *vdev) 87static int virtrng_probe(struct virtio_device *vdev)
@@ -112,7 +99,6 @@ static int virtrng_probe(struct virtio_device *vdev)
112 return err; 99 return err;
113 } 100 }
114 101
115 register_buffer();
116 return 0; 102 return 0;
117} 103}
118 104
@@ -138,21 +124,11 @@ static struct virtio_driver virtio_rng = {
138 124
139static int __init init(void) 125static int __init init(void)
140{ 126{
141 int err; 127 return register_virtio_driver(&virtio_rng);
142
143 random_data = kmalloc(RANDOM_DATA_SIZE, GFP_KERNEL);
144 if (!random_data)
145 return -ENOMEM;
146
147 err = register_virtio_driver(&virtio_rng);
148 if (err)
149 kfree(random_data);
150 return err;
151} 128}
152 129
153static void __exit fini(void) 130static void __exit fini(void)
154{ 131{
155 kfree(random_data);
156 unregister_virtio_driver(&virtio_rng); 132 unregister_virtio_driver(&virtio_rng);
157} 133}
158module_init(init); 134module_init(init);