Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> --- tools/kvm/virtio/rng.c | 254 ++++++++++++++---------------------------------- 1 files changed, 74 insertions(+), 180 deletions(-) diff --git a/tools/kvm/virtio/rng.c b/tools/kvm/virtio/rng.c index 93258f6..5bea56c 100644 --- a/tools/kvm/virtio/rng.c +++ b/tools/kvm/virtio/rng.c @@ -2,16 +2,13 @@ #include "kvm/virtio-pci-dev.h" -#include "kvm/disk-image.h" #include "kvm/virtio.h" -#include "kvm/ioport.h" #include "kvm/util.h" #include "kvm/kvm.h" -#include "kvm/pci.h" #include "kvm/threadpool.h" -#include "kvm/irq.h" #include "kvm/ioeventfd.h" #include "kvm/guest_compat.h" +#include "kvm/virtio-pci.h" #include <linux/virtio_ring.h> #include <linux/virtio_rng.h> @@ -21,6 +18,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <pthread.h> +#include <linux/kernel.h> #define NUM_VIRT_QUEUES 1 #define VIRTIO_RNG_QUEUE_SIZE 128 @@ -32,68 +30,39 @@ struct rng_dev_job { }; struct rng_dev { - struct pci_device_header pci_hdr; struct list_head list; + struct virtio_pci vpci; - u16 base_addr; - u8 status; - u8 isr; - u16 config_vector; int fd; - u32 vq_vector[NUM_VIRT_QUEUES]; - u32 msix_io_block; int compat_id; /* virtio queue */ - u16 queue_selector; struct virt_queue vqs[NUM_VIRT_QUEUES]; struct rng_dev_job jobs[NUM_VIRT_QUEUES]; }; static LIST_HEAD(rdevs); -static bool virtio_rng_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) +static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) { - unsigned long offset; - bool ret = true; - struct rng_dev *rdev; + /* Unused */ +} - rdev = ioport->priv; - offset = port - rdev->base_addr; - - switch (offset) { - case VIRTIO_PCI_HOST_FEATURES: - case VIRTIO_PCI_GUEST_FEATURES: - case VIRTIO_PCI_QUEUE_SEL: - case VIRTIO_PCI_QUEUE_NOTIFY: - ret = false; - break; - case VIRTIO_PCI_QUEUE_PFN: - ioport__write32(data, rdev->vqs[rdev->queue_selector].pfn); - break; - case VIRTIO_PCI_QUEUE_NUM: - ioport__write16(data, VIRTIO_RNG_QUEUE_SIZE); - break; - case VIRTIO_PCI_STATUS: - ioport__write8(data, rdev->status); - break; - case VIRTIO_PCI_ISR: - ioport__write8(data, rdev->isr); - kvm__irq_line(kvm, rdev->pci_hdr.irq_line, VIRTIO_IRQ_LOW); - rdev->isr = VIRTIO_IRQ_LOW; - break; - case VIRTIO_MSI_CONFIG_VECTOR: - ioport__write16(data, rdev->config_vector); - break; - case VIRTIO_MSI_QUEUE_VECTOR: - ioport__write16(data, rdev->vq_vector[rdev->queue_selector]); - break; - default: - ret = false; - break; - }; +static u8 get_config(struct kvm *kvm, void *dev, u32 offset) +{ + /* Unused */ + return 0; +} - return ret; +static u32 get_host_features(struct kvm *kvm, void *dev) +{ + /* Unused */ + return 0; +} + +static void set_guest_features(struct kvm *kvm, void *dev, u32 features) +{ + /* Unused */ } static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue) @@ -119,171 +88,96 @@ static void virtio_rng_do_io(struct kvm *kvm, void *param) while (virt_queue__available(vq)) virtio_rng_do_io_request(kvm, rdev, vq); - kvm__irq_line(kvm, rdev->pci_hdr.irq_line, VIRTIO_IRQ_HIGH); + virtio_pci__signal_vq(kvm, &rdev->vpci, vq - rdev->vqs); } -static bool virtio_rng_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) +static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) { - unsigned long offset; - bool ret = true; - struct rng_dev *rdev; + struct rng_dev *rdev = dev; + struct virt_queue *queue; + struct rng_dev_job *job; + void *p; + struct ioevent ioevent; - rdev = ioport->priv; - offset = port - rdev->base_addr; + compat__remove_message(rdev->compat_id); - switch (offset) { - case VIRTIO_PCI_GUEST_FEATURES: - break; - case VIRTIO_PCI_QUEUE_PFN: { - struct virt_queue *queue; - struct rng_dev_job *job; - void *p; + queue = &rdev->vqs[vq]; + queue->pfn = pfn; + p = guest_pfn_to_host(kvm, queue->pfn); - compat__remove_message(rdev->compat_id); + job = &rdev->jobs[vq]; - queue = &rdev->vqs[rdev->queue_selector]; - queue->pfn = ioport__read32(data); - p = guest_pfn_to_host(kvm, queue->pfn); + vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); - job = &rdev->jobs[rdev->queue_selector]; + *job = (struct rng_dev_job) { + .vq = queue, + .rdev = rdev, + }; - vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); + ioevent = (struct ioevent) { + .io_addr = rdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, + .io_len = sizeof(u16), + .fn = virtio_rng_do_io, + .fn_ptr = &rdev->jobs[vq], + .datamatch = vq, + .fn_kvm = kvm, + .fd = eventfd(0, 0), + }; - *job = (struct rng_dev_job) { - .vq = queue, - .rdev = rdev, - }; + ioeventfd__add_event(&ioevent); - thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job); + thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job); - break; - } - case VIRTIO_PCI_QUEUE_SEL: - rdev->queue_selector = ioport__read16(data); - break; - case VIRTIO_PCI_QUEUE_NOTIFY: { - u16 queue_index; - queue_index = ioport__read16(data); - thread_pool__do_job(&rdev->jobs[queue_index].job_id); - break; - } - case VIRTIO_PCI_STATUS: - rdev->status = ioport__read8(data); - break; - case VIRTIO_MSI_CONFIG_VECTOR: - rdev->config_vector = ioport__read16(data); - break; - case VIRTIO_MSI_QUEUE_VECTOR: { - u32 gsi; - u32 vec; - - vec = rdev->vq_vector[rdev->queue_selector] = ioport__read16(data); - - gsi = irq__add_msix_route(kvm, - rdev->pci_hdr.msix.table[vec].low, - rdev->pci_hdr.msix.table[vec].high, - rdev->pci_hdr.msix.table[vec].data); - rdev->pci_hdr.irq_line = gsi; - break; - } - default: - ret = false; - break; - }; - - return ret; + return 0; } -static struct ioport_operations virtio_rng_io_ops = { - .io_in = virtio_rng_pci_io_in, - .io_out = virtio_rng_pci_io_out, -}; +static int notify_vq(struct kvm *kvm, void *dev, u32 vq) +{ + struct rng_dev *rdev = dev; + + thread_pool__do_job(&rdev->jobs[vq].job_id); -static void ioevent_callback(struct kvm *kvm, void *param) + return 0; +} + +static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) { - struct rng_dev_job *job = param; + struct rng_dev *rdev = dev; - thread_pool__do_job(&job->job_id); + return rdev->vqs[vq].pfn; } -static void callback_mmio(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr) +static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) { - struct rng_dev *rdev = ptr; - void *table = &rdev->pci_hdr.msix.table; - if (is_write) - memcpy(table + addr - rdev->msix_io_block, data, len); - else - memcpy(data, table + addr - rdev->msix_io_block, len); + return VIRTIO_RNG_QUEUE_SIZE; } void virtio_rng__init(struct kvm *kvm) { - u8 pin, line, dev, i; - u16 rdev_base_addr; struct rng_dev *rdev; - struct ioevent ioevent; rdev = malloc(sizeof(*rdev)); if (rdev == NULL) return; - rdev->msix_io_block = pci_get_io_space_block(); - - rdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_rng_io_ops, IOPORT_SIZE, rdev); - kvm__register_mmio(kvm, rdev->msix_io_block, 0x100, callback_mmio, rdev); - - rdev->pci_hdr = (struct pci_device_header) { - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_RNG, - .header_type = PCI_HEADER_TYPE_NORMAL, - .revision_id = 0, - .class = 0x010000, - .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, - .subsys_id = VIRTIO_ID_RNG, - .bar[0] = rdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO, - .bar[1] = rdev->msix_io_block | - PCI_BASE_ADDRESS_SPACE_MEMORY | - PCI_BASE_ADDRESS_MEM_TYPE_64, - /* bar[2] is the continuation of bar[1] for 64bit addressing */ - .bar[2] = 0, - .status = PCI_STATUS_CAP_LIST, - .capabilities = (void *)&rdev->pci_hdr.msix - (void *)&rdev->pci_hdr, - }; - - rdev->pci_hdr.msix.cap = PCI_CAP_ID_MSIX; - rdev->pci_hdr.msix.next = 0; - rdev->pci_hdr.msix.table_size = (NUM_VIRT_QUEUES + 1) | PCI_MSIX_FLAGS_ENABLE; - rdev->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */ - - rdev->config_vector = 0; - rdev->base_addr = rdev_base_addr; rdev->fd = open("/dev/urandom", O_RDONLY); if (rdev->fd < 0) die("Failed initializing RNG"); - if (irq__register_device(VIRTIO_ID_RNG, &dev, &pin, &line) < 0) - return; - - rdev->pci_hdr.irq_pin = pin; - rdev->pci_hdr.irq_line = line; - pci__register(&rdev->pci_hdr, dev); + virtio_pci__init(kvm, &rdev->vpci, rdev, PCI_DEVICE_ID_VIRTIO_RNG, VIRTIO_ID_RNG); + rdev->vpci.ops = (struct virtio_pci_ops) { + .set_config = set_config, + .get_config = get_config, + .get_host_features = get_host_features, + .set_guest_features = set_guest_features, + .init_vq = init_vq, + .notify_vq = notify_vq, + .get_pfn_vq = get_pfn_vq, + .get_size_vq = get_size_vq, + }; list_add_tail(&rdev->list, &rdevs); - for (i = 0; i < NUM_VIRT_QUEUES; i++) { - ioevent = (struct ioevent) { - .io_addr = rdev_base_addr + VIRTIO_PCI_QUEUE_NOTIFY, - .io_len = sizeof(u16), - .fn = ioevent_callback, - .fn_ptr = &rdev->jobs[i], - .datamatch = i, - .fn_kvm = kvm, - .fd = eventfd(0, 0), - }; - - ioeventfd__add_event(&ioevent); - } - rdev->compat_id = compat__add_message("virtio-rng device was not detected", "While you have requested a virtio-rng device, " "the guest kernel didn't seem to detect it.\n" @@ -298,7 +192,7 @@ void virtio_rng__delete_all(struct kvm *kvm) rdev = list_first_entry(&rdevs, struct rng_dev, list); list_del(&rdev->list); - ioeventfd__del_event(rdev->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 0); + ioeventfd__del_event(rdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 0); free(rdev); } } -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html