From patchwork Sat Apr 30 13:30:24 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sasha Levin X-Patchwork-Id: 743382 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.3) with ESMTP id p3UDUfHG001246 for ; Sat, 30 Apr 2011 13:30:41 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756839Ab1D3Nah (ORCPT ); Sat, 30 Apr 2011 09:30:37 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:33344 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756810Ab1D3Naf (ORCPT ); Sat, 30 Apr 2011 09:30:35 -0400 Received: by mail-bw0-f46.google.com with SMTP id 15so3694296bwz.19 for ; Sat, 30 Apr 2011 06:30:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=WMjQOYCkdo1cA7KWQ40uoKi0XrqIodd9My2xdeWlGcQ=; b=Jax0NlBRwi0wP68W8Vs6Xc+zlo29BbIT+8IdkGwJgecgz16RxcUSukDhHginaaCVys vhi7IssQZjbE+xgKdDRvssAiiJbW3LeHQxkw0MwLvvhUM1SAYimxAlNhNSXVmIp80qyz zfR/My0q9V3s69GEXB4YqLDZ1Z6ApIWaM1Mi0= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=UMZQFDl1kmxW9l8EgGf0SV0io5DCUPEPz+VRT4FXJtA+mogo4Xrr1bVwLXlMVFjVg9 DMNlx/fHCm1LsIdG+kEjDyzn5iTkHJ9nU3dZtTUvkyssLF9fw7nxLkLAmGG2OdTEFBNC 2oQ6Kq/XItbL/MDuPtD0a23VR/sBm17Tb9ytM= Received: by 10.204.136.210 with SMTP id s18mr1221192bkt.56.1304170234831; Sat, 30 Apr 2011 06:30:34 -0700 (PDT) Received: from localhost.localdomain ([94.230.82.242]) by mx.google.com with ESMTPS id q24sm2169224bks.21.2011.04.30.06.30.33 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 30 Apr 2011 06:30:34 -0700 (PDT) From: Sasha Levin To: penberg@kernel.org Cc: mingo@elte.hu, asias.hejun@gmail.com, gorcunov@gmail.com, prasadjoshi124@gmail.com, kvm@vger.kernel.org, Sasha Levin Subject: [PATCH 2/3] kvm tools: Introduce virtio-rng Date: Sat, 30 Apr 2011 16:30:24 +0300 Message-Id: <1304170225-4859-2-git-send-email-levinsasha928@gmail.com> X-Mailer: git-send-email 1.7.5.rc3 In-Reply-To: <1304170225-4859-1-git-send-email-levinsasha928@gmail.com> References: <1304170225-4859-1-git-send-email-levinsasha928@gmail.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sat, 30 Apr 2011 13:30:41 +0000 (UTC) Enable virtio-rng, a virtio random number generator. Guest kernel should be compiled with CONFIG_HW_RANDOM_VIRTIO. Once enabled, A RNG device will be located at /dev/hwrng. Signed-off-by: Sasha Levin --- tools/kvm/Makefile | 1 + tools/kvm/include/kvm/ioport.h | 2 + tools/kvm/include/kvm/virtio-rng.h | 8 ++ tools/kvm/virtio-rng.c | 184 ++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 0 deletions(-) create mode 100644 tools/kvm/include/kvm/virtio-rng.h create mode 100644 tools/kvm/virtio-rng.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index 659bc35..19e7b9e 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -38,6 +38,7 @@ OBJS += kvm-run.o OBJS += qcow.o OBJS += mptable.o OBJS += threadpool.o +OBJS += virtio-rng.o DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h index 2fdcca4..6020124 100644 --- a/tools/kvm/include/kvm/ioport.h +++ b/tools/kvm/include/kvm/ioport.h @@ -12,6 +12,8 @@ #define IOPORT_VIRTIO_CONSOLE_SIZE 256 #define IOPORT_VIRTIO_NET 0xe200 /* Virtio network device */ #define IOPORT_VIRTIO_NET_SIZE 256 +#define IOPORT_VIRTIO_RNG 0xf200 /* Virtio network device */ +#define IOPORT_VIRTIO_RNG_SIZE 256 struct kvm; diff --git a/tools/kvm/include/kvm/virtio-rng.h b/tools/kvm/include/kvm/virtio-rng.h new file mode 100644 index 0000000..7015c1f --- /dev/null +++ b/tools/kvm/include/kvm/virtio-rng.h @@ -0,0 +1,8 @@ +#ifndef KVM__RNG_VIRTIO_H +#define KVM__RNG_VIRTIO_H + +struct kvm; + +void virtio_rng__init(struct kvm *kvm); + +#endif /* KVM__RNG_VIRTIO_H */ diff --git a/tools/kvm/virtio-rng.c b/tools/kvm/virtio-rng.c new file mode 100644 index 0000000..d37fb5e --- /dev/null +++ b/tools/kvm/virtio-rng.c @@ -0,0 +1,184 @@ +#include "kvm/virtio-rng.h" + +#include "kvm/virtio-pci.h" + +#include "kvm/disk-image.h" +#include "kvm/virtio.h" +#include "kvm/ioport.h" +#include "kvm/mutex.h" +#include "kvm/util.h" +#include "kvm/kvm.h" +#include "kvm/pci.h" +#include "kvm/threadpool.h" + +#include +#include + +#include +#include +#include +#include +#include + +#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_DEVICE_ID_VIRTIO_RNG 0x1004 +#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_SUBSYSTEM_ID_VIRTIO_RNG 0x0004 +#define PCI_VIRTIO_RNG_DEVNUM 4 + +#define VIRTIO_RNG_IRQ 11 +#define VIRTIO_RNG_PIN 1 + +#define NUM_VIRT_QUEUES 1 + +#define VIRTIO_RNG_QUEUE_SIZE 128 + +struct rng_device { + uint8_t status; + uint16_t config_vector; + int fd_rng; + + /* virtio queue */ + uint16_t queue_selector; + struct virt_queue vqs[NUM_VIRT_QUEUES]; + void *jobs[NUM_VIRT_QUEUES]; +}; + +static struct rng_device rng_device; + +static bool virtio_rng_pci_io_in(struct kvm *kvm, uint16_t port, void *data, int size, uint32_t count) +{ + unsigned long offset; + bool ret = true; + + offset = port - IOPORT_VIRTIO_RNG; + + 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, rng_device.vqs[rng_device.queue_selector].pfn); + break; + case VIRTIO_PCI_QUEUE_NUM: + ioport__write16(data, VIRTIO_RNG_QUEUE_SIZE); + break; + case VIRTIO_PCI_STATUS: + ioport__write8(data, rng_device.status); + break; + case VIRTIO_PCI_ISR: + ioport__write8(data, 0x1); + kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 0); + break; + case VIRTIO_MSI_CONFIG_VECTOR: + ioport__write16(data, rng_device.config_vector); + break; + default: + ret = false; + }; + + return ret; +} + +static bool virtio_rng_do_io_request(struct kvm *self, struct virt_queue *queue) +{ + struct iovec iov[VIRTIO_RNG_QUEUE_SIZE]; + uint16_t out, in, head; + unsigned int len = 0; + + head = virt_queue__get_iov(queue, iov, &out, &in, self); + len = readv(rng_device.fd_rng, iov, in); + virt_queue__set_used_elem(queue, head, len); + + return true; +} + +static void virtio_rng_do_io(struct kvm *kvm, void *param) +{ + struct virt_queue *vq = param; + + while (virt_queue__available(vq)) { + virtio_rng_do_io_request(kvm, vq); + kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 1); + } +} + +static bool virtio_rng_pci_io_out(struct kvm *kvm, uint16_t port, void *data, int size, uint32_t count) +{ + unsigned long offset; + bool ret = true; + + offset = port - IOPORT_VIRTIO_RNG; + + switch (offset) { + case VIRTIO_MSI_QUEUE_VECTOR: + case VIRTIO_PCI_GUEST_FEATURES: + break; + case VIRTIO_PCI_QUEUE_PFN: { + struct virt_queue *queue; + void *p; + + queue = &rng_device.vqs[rng_device.queue_selector]; + queue->pfn = ioport__read32(data); + p = guest_flat_to_host(kvm, queue->pfn << 12); + + vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, 4096); + + rng_device.jobs[rng_device.queue_selector] = + thread_pool__add_jobtype(kvm, virtio_rng_do_io, queue); + + break; + } + case VIRTIO_PCI_QUEUE_SEL: + rng_device.queue_selector = ioport__read16(data); + break; + case VIRTIO_PCI_QUEUE_NOTIFY: { + uint16_t queue_index; + queue_index = ioport__read16(data); + thread_pool__signal_work(rng_device.jobs[queue_index]); + break; + } + case VIRTIO_PCI_STATUS: + rng_device.status = ioport__read8(data); + break; + case VIRTIO_MSI_CONFIG_VECTOR: + rng_device.config_vector = VIRTIO_MSI_NO_VECTOR; + break; + default: + ret = false; + }; + + return ret; +} + +static struct ioport_operations virtio_rng_io_ops = { + .io_in = virtio_rng_pci_io_in, + .io_out = virtio_rng_pci_io_out, +}; + +static struct pci_device_header virtio_rng_pci_device = { + .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 = PCI_SUBSYSTEM_ID_VIRTIO_RNG, + .bar[0] = IOPORT_VIRTIO_RNG | PCI_BASE_ADDRESS_SPACE_IO, + .irq_pin = VIRTIO_RNG_PIN, + .irq_line = VIRTIO_RNG_IRQ, +}; + +void virtio_rng__init(struct kvm *kvm) +{ + rng_device.fd_rng = open("/dev/urandom", O_RDONLY); + if (rng_device.fd_rng < 0) + die("Failed initializing RNG"); + + pci__register(&virtio_rng_pci_device, PCI_VIRTIO_RNG_DEVNUM); + + ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE); +}