1*376ac44cSSasha Levin #include "kvm/virtio-rng.h" 2*376ac44cSSasha Levin 3*376ac44cSSasha Levin #include "kvm/virtio-pci.h" 4*376ac44cSSasha Levin 5*376ac44cSSasha Levin #include "kvm/disk-image.h" 6*376ac44cSSasha Levin #include "kvm/virtio.h" 7*376ac44cSSasha Levin #include "kvm/ioport.h" 8*376ac44cSSasha Levin #include "kvm/mutex.h" 9*376ac44cSSasha Levin #include "kvm/util.h" 10*376ac44cSSasha Levin #include "kvm/kvm.h" 11*376ac44cSSasha Levin #include "kvm/pci.h" 12*376ac44cSSasha Levin #include "kvm/threadpool.h" 13*376ac44cSSasha Levin 14*376ac44cSSasha Levin #include <linux/virtio_ring.h> 15*376ac44cSSasha Levin #include <linux/virtio_rng.h> 16*376ac44cSSasha Levin 17*376ac44cSSasha Levin #include <fcntl.h> 18*376ac44cSSasha Levin #include <sys/types.h> 19*376ac44cSSasha Levin #include <sys/stat.h> 20*376ac44cSSasha Levin #include <inttypes.h> 21*376ac44cSSasha Levin #include <pthread.h> 22*376ac44cSSasha Levin 23*376ac44cSSasha Levin #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 24*376ac44cSSasha Levin #define PCI_DEVICE_ID_VIRTIO_RNG 0x1004 25*376ac44cSSasha Levin #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 26*376ac44cSSasha Levin #define PCI_SUBSYSTEM_ID_VIRTIO_RNG 0x0004 27*376ac44cSSasha Levin #define PCI_VIRTIO_RNG_DEVNUM 4 28*376ac44cSSasha Levin 29*376ac44cSSasha Levin #define VIRTIO_RNG_IRQ 11 30*376ac44cSSasha Levin #define VIRTIO_RNG_PIN 1 31*376ac44cSSasha Levin 32*376ac44cSSasha Levin #define NUM_VIRT_QUEUES 1 33*376ac44cSSasha Levin 34*376ac44cSSasha Levin #define VIRTIO_RNG_QUEUE_SIZE 128 35*376ac44cSSasha Levin 36*376ac44cSSasha Levin struct rng_device { 37*376ac44cSSasha Levin uint8_t status; 38*376ac44cSSasha Levin uint16_t config_vector; 39*376ac44cSSasha Levin int fd_rng; 40*376ac44cSSasha Levin 41*376ac44cSSasha Levin /* virtio queue */ 42*376ac44cSSasha Levin uint16_t queue_selector; 43*376ac44cSSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 44*376ac44cSSasha Levin void *jobs[NUM_VIRT_QUEUES]; 45*376ac44cSSasha Levin }; 46*376ac44cSSasha Levin 47*376ac44cSSasha Levin static struct rng_device rng_device; 48*376ac44cSSasha Levin 49*376ac44cSSasha Levin static bool virtio_rng_pci_io_in(struct kvm *kvm, uint16_t port, void *data, int size, uint32_t count) 50*376ac44cSSasha Levin { 51*376ac44cSSasha Levin unsigned long offset; 52*376ac44cSSasha Levin bool ret = true; 53*376ac44cSSasha Levin 54*376ac44cSSasha Levin offset = port - IOPORT_VIRTIO_RNG; 55*376ac44cSSasha Levin 56*376ac44cSSasha Levin switch (offset) { 57*376ac44cSSasha Levin case VIRTIO_PCI_HOST_FEATURES: 58*376ac44cSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 59*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 60*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 61*376ac44cSSasha Levin ret = false; 62*376ac44cSSasha Levin break; 63*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_PFN: 64*376ac44cSSasha Levin ioport__write32(data, rng_device.vqs[rng_device.queue_selector].pfn); 65*376ac44cSSasha Levin break; 66*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_NUM: 67*376ac44cSSasha Levin ioport__write16(data, VIRTIO_RNG_QUEUE_SIZE); 68*376ac44cSSasha Levin break; 69*376ac44cSSasha Levin case VIRTIO_PCI_STATUS: 70*376ac44cSSasha Levin ioport__write8(data, rng_device.status); 71*376ac44cSSasha Levin break; 72*376ac44cSSasha Levin case VIRTIO_PCI_ISR: 73*376ac44cSSasha Levin ioport__write8(data, 0x1); 74*376ac44cSSasha Levin kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 0); 75*376ac44cSSasha Levin break; 76*376ac44cSSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 77*376ac44cSSasha Levin ioport__write16(data, rng_device.config_vector); 78*376ac44cSSasha Levin break; 79*376ac44cSSasha Levin default: 80*376ac44cSSasha Levin ret = false; 81*376ac44cSSasha Levin }; 82*376ac44cSSasha Levin 83*376ac44cSSasha Levin return ret; 84*376ac44cSSasha Levin } 85*376ac44cSSasha Levin 86*376ac44cSSasha Levin static bool virtio_rng_do_io_request(struct kvm *self, struct virt_queue *queue) 87*376ac44cSSasha Levin { 88*376ac44cSSasha Levin struct iovec iov[VIRTIO_RNG_QUEUE_SIZE]; 89*376ac44cSSasha Levin uint16_t out, in, head; 90*376ac44cSSasha Levin unsigned int len = 0; 91*376ac44cSSasha Levin 92*376ac44cSSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, self); 93*376ac44cSSasha Levin len = readv(rng_device.fd_rng, iov, in); 94*376ac44cSSasha Levin virt_queue__set_used_elem(queue, head, len); 95*376ac44cSSasha Levin 96*376ac44cSSasha Levin return true; 97*376ac44cSSasha Levin } 98*376ac44cSSasha Levin 99*376ac44cSSasha Levin static void virtio_rng_do_io(struct kvm *kvm, void *param) 100*376ac44cSSasha Levin { 101*376ac44cSSasha Levin struct virt_queue *vq = param; 102*376ac44cSSasha Levin 103*376ac44cSSasha Levin while (virt_queue__available(vq)) { 104*376ac44cSSasha Levin virtio_rng_do_io_request(kvm, vq); 105*376ac44cSSasha Levin kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 1); 106*376ac44cSSasha Levin } 107*376ac44cSSasha Levin } 108*376ac44cSSasha Levin 109*376ac44cSSasha Levin static bool virtio_rng_pci_io_out(struct kvm *kvm, uint16_t port, void *data, int size, uint32_t count) 110*376ac44cSSasha Levin { 111*376ac44cSSasha Levin unsigned long offset; 112*376ac44cSSasha Levin bool ret = true; 113*376ac44cSSasha Levin 114*376ac44cSSasha Levin offset = port - IOPORT_VIRTIO_RNG; 115*376ac44cSSasha Levin 116*376ac44cSSasha Levin switch (offset) { 117*376ac44cSSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 118*376ac44cSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 119*376ac44cSSasha Levin break; 120*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 121*376ac44cSSasha Levin struct virt_queue *queue; 122*376ac44cSSasha Levin void *p; 123*376ac44cSSasha Levin 124*376ac44cSSasha Levin queue = &rng_device.vqs[rng_device.queue_selector]; 125*376ac44cSSasha Levin queue->pfn = ioport__read32(data); 126*376ac44cSSasha Levin p = guest_flat_to_host(kvm, queue->pfn << 12); 127*376ac44cSSasha Levin 128*376ac44cSSasha Levin vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, 4096); 129*376ac44cSSasha Levin 130*376ac44cSSasha Levin rng_device.jobs[rng_device.queue_selector] = 131*376ac44cSSasha Levin thread_pool__add_jobtype(kvm, virtio_rng_do_io, queue); 132*376ac44cSSasha Levin 133*376ac44cSSasha Levin break; 134*376ac44cSSasha Levin } 135*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 136*376ac44cSSasha Levin rng_device.queue_selector = ioport__read16(data); 137*376ac44cSSasha Levin break; 138*376ac44cSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 139*376ac44cSSasha Levin uint16_t queue_index; 140*376ac44cSSasha Levin queue_index = ioport__read16(data); 141*376ac44cSSasha Levin thread_pool__signal_work(rng_device.jobs[queue_index]); 142*376ac44cSSasha Levin break; 143*376ac44cSSasha Levin } 144*376ac44cSSasha Levin case VIRTIO_PCI_STATUS: 145*376ac44cSSasha Levin rng_device.status = ioport__read8(data); 146*376ac44cSSasha Levin break; 147*376ac44cSSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 148*376ac44cSSasha Levin rng_device.config_vector = VIRTIO_MSI_NO_VECTOR; 149*376ac44cSSasha Levin break; 150*376ac44cSSasha Levin default: 151*376ac44cSSasha Levin ret = false; 152*376ac44cSSasha Levin }; 153*376ac44cSSasha Levin 154*376ac44cSSasha Levin return ret; 155*376ac44cSSasha Levin } 156*376ac44cSSasha Levin 157*376ac44cSSasha Levin static struct ioport_operations virtio_rng_io_ops = { 158*376ac44cSSasha Levin .io_in = virtio_rng_pci_io_in, 159*376ac44cSSasha Levin .io_out = virtio_rng_pci_io_out, 160*376ac44cSSasha Levin }; 161*376ac44cSSasha Levin 162*376ac44cSSasha Levin static struct pci_device_header virtio_rng_pci_device = { 163*376ac44cSSasha Levin .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 164*376ac44cSSasha Levin .device_id = PCI_DEVICE_ID_VIRTIO_RNG, 165*376ac44cSSasha Levin .header_type = PCI_HEADER_TYPE_NORMAL, 166*376ac44cSSasha Levin .revision_id = 0, 167*376ac44cSSasha Levin .class = 0x010000, 168*376ac44cSSasha Levin .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 169*376ac44cSSasha Levin .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_RNG, 170*376ac44cSSasha Levin .bar[0] = IOPORT_VIRTIO_RNG | PCI_BASE_ADDRESS_SPACE_IO, 171*376ac44cSSasha Levin .irq_pin = VIRTIO_RNG_PIN, 172*376ac44cSSasha Levin .irq_line = VIRTIO_RNG_IRQ, 173*376ac44cSSasha Levin }; 174*376ac44cSSasha Levin 175*376ac44cSSasha Levin void virtio_rng__init(struct kvm *kvm) 176*376ac44cSSasha Levin { 177*376ac44cSSasha Levin rng_device.fd_rng = open("/dev/urandom", O_RDONLY); 178*376ac44cSSasha Levin if (rng_device.fd_rng < 0) 179*376ac44cSSasha Levin die("Failed initializing RNG"); 180*376ac44cSSasha Levin 181*376ac44cSSasha Levin pci__register(&virtio_rng_pci_device, PCI_VIRTIO_RNG_DEVNUM); 182*376ac44cSSasha Levin 183*376ac44cSSasha Levin ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE); 184*376ac44cSSasha Levin } 185