1 /* 2 * Randomness driver for virtio 3 * Copyright (C) 2007, 2008 Rusty Russell IBM Corporation 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 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 18 */ 19 #include <linux/err.h> 20 #include <linux/hw_random.h> 21 #include <linux/scatterlist.h> 22 #include <linux/spinlock.h> 23 #include <linux/virtio.h> 24 #include <linux/virtio_ids.h> 25 #include <linux/virtio_rng.h> 26 27 /* The host will fill any buffer we give it with sweet, sweet randomness. We 28 * give it 64 bytes at a time, and the hwrng framework takes it 4 bytes at a 29 * time. */ 30 #define RANDOM_DATA_SIZE 64 31 32 static struct virtqueue *vq; 33 static u32 *random_data; 34 static unsigned int data_left; 35 static DECLARE_COMPLETION(have_data); 36 37 static void random_recv_done(struct virtqueue *vq) 38 { 39 unsigned int len; 40 41 /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ 42 if (!vq->vq_ops->get_buf(vq, &len)) 43 return; 44 45 data_left += len; 46 complete(&have_data); 47 } 48 49 static void register_buffer(void) 50 { 51 struct scatterlist sg; 52 53 sg_init_one(&sg, random_data+data_left, RANDOM_DATA_SIZE-data_left); 54 /* There should always be room for one buffer. */ 55 if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) < 0) 56 BUG(); 57 vq->vq_ops->kick(vq); 58 } 59 60 /* At least we don't udelay() in a loop like some other drivers. */ 61 static int virtio_data_present(struct hwrng *rng, int wait) 62 { 63 if (data_left >= sizeof(u32)) 64 return 1; 65 66 again: 67 if (!wait) 68 return 0; 69 70 wait_for_completion(&have_data); 71 72 /* Not enough? Re-register. */ 73 if (unlikely(data_left < sizeof(u32))) { 74 register_buffer(); 75 goto again; 76 } 77 78 return 1; 79 } 80 81 /* virtio_data_present() must have succeeded before this is called. */ 82 static int virtio_data_read(struct hwrng *rng, u32 *data) 83 { 84 BUG_ON(data_left < sizeof(u32)); 85 data_left -= sizeof(u32); 86 *data = random_data[data_left / 4]; 87 88 if (data_left < sizeof(u32)) { 89 init_completion(&have_data); 90 register_buffer(); 91 } 92 return sizeof(*data); 93 } 94 95 static struct hwrng virtio_hwrng = { 96 .name = "virtio", 97 .data_present = virtio_data_present, 98 .data_read = virtio_data_read, 99 }; 100 101 static int virtrng_probe(struct virtio_device *vdev) 102 { 103 int err; 104 105 /* We expect a single virtqueue. */ 106 vq = virtio_find_single_vq(vdev, random_recv_done, "input"); 107 if (IS_ERR(vq)) 108 return PTR_ERR(vq); 109 110 err = hwrng_register(&virtio_hwrng); 111 if (err) { 112 vdev->config->del_vqs(vdev); 113 return err; 114 } 115 116 register_buffer(); 117 return 0; 118 } 119 120 static void virtrng_remove(struct virtio_device *vdev) 121 { 122 vdev->config->reset(vdev); 123 hwrng_unregister(&virtio_hwrng); 124 vdev->config->del_vqs(vdev); 125 } 126 127 static struct virtio_device_id id_table[] = { 128 { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, 129 { 0 }, 130 }; 131 132 static struct virtio_driver virtio_rng = { 133 .driver.name = KBUILD_MODNAME, 134 .driver.owner = THIS_MODULE, 135 .id_table = id_table, 136 .probe = virtrng_probe, 137 .remove = __devexit_p(virtrng_remove), 138 }; 139 140 static int __init init(void) 141 { 142 int err; 143 144 random_data = kmalloc(RANDOM_DATA_SIZE, GFP_KERNEL); 145 if (!random_data) 146 return -ENOMEM; 147 148 err = register_virtio_driver(&virtio_rng); 149 if (err) 150 kfree(random_data); 151 return err; 152 } 153 154 static void __exit fini(void) 155 { 156 kfree(random_data); 157 unregister_virtio_driver(&virtio_rng); 158 } 159 module_init(init); 160 module_exit(fini); 161 162 MODULE_DEVICE_TABLE(virtio, id_table); 163 MODULE_DESCRIPTION("Virtio random number driver"); 164 MODULE_LICENSE("GPL"); 165