1376ac44cSSasha Levin #include "kvm/virtio-rng.h" 2376ac44cSSasha Levin 331638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h" 4376ac44cSSasha Levin 5376ac44cSSasha Levin #include "kvm/virtio.h" 6376ac44cSSasha Levin #include "kvm/util.h" 7376ac44cSSasha Levin #include "kvm/kvm.h" 8376ac44cSSasha Levin #include "kvm/threadpool.h" 9b2533581SSasha Levin #include "kvm/ioeventfd.h" 10c75b037fSSasha Levin #include "kvm/guest_compat.h" 11*53cbeb9bSSasha Levin #include "kvm/virtio-pci.h" 12376ac44cSSasha Levin 13376ac44cSSasha Levin #include <linux/virtio_ring.h> 14376ac44cSSasha Levin #include <linux/virtio_rng.h> 15376ac44cSSasha Levin 1680ac1d05SSasha Levin #include <linux/list.h> 17376ac44cSSasha Levin #include <fcntl.h> 18376ac44cSSasha Levin #include <sys/types.h> 19376ac44cSSasha Levin #include <sys/stat.h> 20376ac44cSSasha Levin #include <pthread.h> 21*53cbeb9bSSasha Levin #include <linux/kernel.h> 22376ac44cSSasha Levin 23376ac44cSSasha Levin #define NUM_VIRT_QUEUES 1 24376ac44cSSasha Levin #define VIRTIO_RNG_QUEUE_SIZE 128 25376ac44cSSasha Levin 2680ac1d05SSasha Levin struct rng_dev_job { 2780ac1d05SSasha Levin struct virt_queue *vq; 2880ac1d05SSasha Levin struct rng_dev *rdev; 29df0c7f57SSasha Levin struct thread_pool__job job_id; 302449f6e3SSasha Levin }; 312449f6e3SSasha Levin 3280ffe4d1SSasha Levin struct rng_dev { 3380ac1d05SSasha Levin struct list_head list; 34*53cbeb9bSSasha Levin struct virtio_pci vpci; 3580ac1d05SSasha Levin 3680ffe4d1SSasha Levin int fd; 37c75b037fSSasha Levin int compat_id; 38376ac44cSSasha Levin 39376ac44cSSasha Levin /* virtio queue */ 40376ac44cSSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 4180ac1d05SSasha Levin struct rng_dev_job jobs[NUM_VIRT_QUEUES]; 42376ac44cSSasha Levin }; 43376ac44cSSasha Levin 4480ac1d05SSasha Levin static LIST_HEAD(rdevs); 45376ac44cSSasha Levin 46*53cbeb9bSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 47376ac44cSSasha Levin { 48*53cbeb9bSSasha Levin /* Unused */ 49*53cbeb9bSSasha Levin } 50376ac44cSSasha Levin 51*53cbeb9bSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 52*53cbeb9bSSasha Levin { 53*53cbeb9bSSasha Levin /* Unused */ 54*53cbeb9bSSasha Levin return 0; 55*53cbeb9bSSasha Levin } 56376ac44cSSasha Levin 57*53cbeb9bSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 58*53cbeb9bSSasha Levin { 59*53cbeb9bSSasha Levin /* Unused */ 60*53cbeb9bSSasha Levin return 0; 61*53cbeb9bSSasha Levin } 62376ac44cSSasha Levin 63*53cbeb9bSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 64*53cbeb9bSSasha Levin { 65*53cbeb9bSSasha Levin /* Unused */ 66376ac44cSSasha Levin } 67376ac44cSSasha Levin 6880ac1d05SSasha Levin static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue) 69376ac44cSSasha Levin { 70376ac44cSSasha Levin struct iovec iov[VIRTIO_RNG_QUEUE_SIZE]; 71376ac44cSSasha Levin unsigned int len = 0; 72407475bfSPekka Enberg u16 out, in, head; 73376ac44cSSasha Levin 7480ffe4d1SSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, kvm); 7580ac1d05SSasha Levin len = readv(rdev->fd, iov, in); 76407475bfSPekka Enberg 77376ac44cSSasha Levin virt_queue__set_used_elem(queue, head, len); 78376ac44cSSasha Levin 79376ac44cSSasha Levin return true; 80376ac44cSSasha Levin } 81376ac44cSSasha Levin 82376ac44cSSasha Levin static void virtio_rng_do_io(struct kvm *kvm, void *param) 83376ac44cSSasha Levin { 8480ac1d05SSasha Levin struct rng_dev_job *job = param; 8580ac1d05SSasha Levin struct virt_queue *vq = job->vq; 8680ac1d05SSasha Levin struct rng_dev *rdev = job->rdev; 87376ac44cSSasha Levin 88bc485053SSasha Levin while (virt_queue__available(vq)) 8980ac1d05SSasha Levin virtio_rng_do_io_request(kvm, rdev, vq); 90bc485053SSasha Levin 91*53cbeb9bSSasha Levin virtio_pci__signal_vq(kvm, &rdev->vpci, vq - rdev->vqs); 92376ac44cSSasha Levin } 93376ac44cSSasha Levin 94*53cbeb9bSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 95376ac44cSSasha Levin { 96*53cbeb9bSSasha Levin struct rng_dev *rdev = dev; 97376ac44cSSasha Levin struct virt_queue *queue; 9880ac1d05SSasha Levin struct rng_dev_job *job; 99376ac44cSSasha Levin void *p; 100*53cbeb9bSSasha Levin struct ioevent ioevent; 101376ac44cSSasha Levin 102c75b037fSSasha Levin compat__remove_message(rdev->compat_id); 103c75b037fSSasha Levin 104*53cbeb9bSSasha Levin queue = &rdev->vqs[vq]; 105*53cbeb9bSSasha Levin queue->pfn = pfn; 106aaf0b445SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 107376ac44cSSasha Levin 108*53cbeb9bSSasha Levin job = &rdev->jobs[vq]; 10980ac1d05SSasha Levin 110b8f43678SSasha Levin vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 111376ac44cSSasha Levin 11280ac1d05SSasha Levin *job = (struct rng_dev_job) { 11380ac1d05SSasha Levin .vq = queue, 11480ac1d05SSasha Levin .rdev = rdev, 11580ac1d05SSasha Levin }; 11680ac1d05SSasha Levin 117b2533581SSasha Levin ioevent = (struct ioevent) { 118*53cbeb9bSSasha Levin .io_addr = rdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 119b2533581SSasha Levin .io_len = sizeof(u16), 120*53cbeb9bSSasha Levin .fn = virtio_rng_do_io, 121*53cbeb9bSSasha Levin .fn_ptr = &rdev->jobs[vq], 122*53cbeb9bSSasha Levin .datamatch = vq, 123b2533581SSasha Levin .fn_kvm = kvm, 124b2533581SSasha Levin .fd = eventfd(0, 0), 125b2533581SSasha Levin }; 126b2533581SSasha Levin 127b2533581SSasha Levin ioeventfd__add_event(&ioevent); 128*53cbeb9bSSasha Levin 129*53cbeb9bSSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job); 130*53cbeb9bSSasha Levin 131*53cbeb9bSSasha Levin return 0; 132b2533581SSasha Levin } 133c75b037fSSasha Levin 134*53cbeb9bSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 135*53cbeb9bSSasha Levin { 136*53cbeb9bSSasha Levin struct rng_dev *rdev = dev; 137*53cbeb9bSSasha Levin 138*53cbeb9bSSasha Levin thread_pool__do_job(&rdev->jobs[vq].job_id); 139*53cbeb9bSSasha Levin 140*53cbeb9bSSasha Levin return 0; 141*53cbeb9bSSasha Levin } 142*53cbeb9bSSasha Levin 143*53cbeb9bSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 144*53cbeb9bSSasha Levin { 145*53cbeb9bSSasha Levin struct rng_dev *rdev = dev; 146*53cbeb9bSSasha Levin 147*53cbeb9bSSasha Levin return rdev->vqs[vq].pfn; 148*53cbeb9bSSasha Levin } 149*53cbeb9bSSasha Levin 150*53cbeb9bSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 151*53cbeb9bSSasha Levin { 152*53cbeb9bSSasha Levin return VIRTIO_RNG_QUEUE_SIZE; 153*53cbeb9bSSasha Levin } 154*53cbeb9bSSasha Levin 155*53cbeb9bSSasha Levin void virtio_rng__init(struct kvm *kvm) 156*53cbeb9bSSasha Levin { 157*53cbeb9bSSasha Levin struct rng_dev *rdev; 158*53cbeb9bSSasha Levin 159*53cbeb9bSSasha Levin rdev = malloc(sizeof(*rdev)); 160*53cbeb9bSSasha Levin if (rdev == NULL) 161*53cbeb9bSSasha Levin return; 162*53cbeb9bSSasha Levin 163*53cbeb9bSSasha Levin rdev->fd = open("/dev/urandom", O_RDONLY); 164*53cbeb9bSSasha Levin if (rdev->fd < 0) 165*53cbeb9bSSasha Levin die("Failed initializing RNG"); 166*53cbeb9bSSasha Levin 167*53cbeb9bSSasha Levin virtio_pci__init(kvm, &rdev->vpci, rdev, PCI_DEVICE_ID_VIRTIO_RNG, VIRTIO_ID_RNG); 168*53cbeb9bSSasha Levin rdev->vpci.ops = (struct virtio_pci_ops) { 169*53cbeb9bSSasha Levin .set_config = set_config, 170*53cbeb9bSSasha Levin .get_config = get_config, 171*53cbeb9bSSasha Levin .get_host_features = get_host_features, 172*53cbeb9bSSasha Levin .set_guest_features = set_guest_features, 173*53cbeb9bSSasha Levin .init_vq = init_vq, 174*53cbeb9bSSasha Levin .notify_vq = notify_vq, 175*53cbeb9bSSasha Levin .get_pfn_vq = get_pfn_vq, 176*53cbeb9bSSasha Levin .get_size_vq = get_size_vq, 177*53cbeb9bSSasha Levin }; 178*53cbeb9bSSasha Levin 179*53cbeb9bSSasha Levin list_add_tail(&rdev->list, &rdevs); 180*53cbeb9bSSasha Levin 181c75b037fSSasha Levin rdev->compat_id = compat__add_message("virtio-rng device was not detected", 182c75b037fSSasha Levin "While you have requested a virtio-rng device, " 183c75b037fSSasha Levin "the guest kernel didn't seem to detect it.\n" 184c75b037fSSasha Levin "Please make sure that the kernel was compiled" 185c75b037fSSasha Levin "with CONFIG_HW_RANDOM_VIRTIO."); 18680ac1d05SSasha Levin } 18780ac1d05SSasha Levin 18880ac1d05SSasha Levin void virtio_rng__delete_all(struct kvm *kvm) 18980ac1d05SSasha Levin { 19080ac1d05SSasha Levin while (!list_empty(&rdevs)) { 19180ac1d05SSasha Levin struct rng_dev *rdev; 19280ac1d05SSasha Levin 19380ac1d05SSasha Levin rdev = list_first_entry(&rdevs, struct rng_dev, list); 19480ac1d05SSasha Levin list_del(&rdev->list); 195*53cbeb9bSSasha Levin ioeventfd__del_event(rdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 0); 19680ac1d05SSasha Levin free(rdev); 19780ac1d05SSasha Levin } 198376ac44cSSasha Levin } 199