qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: Ian Molton <ian.molton@collabora.co.uk>
Cc: Paul Brook <paul@codesourcery.com>,
	qemu-devel@nongnu.org, Gerd Hoffmann <kraxel@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 2/2] VirtIO RNG
Date: Mon, 03 May 2010 12:56:38 -0500	[thread overview]
Message-ID: <4BDF0E56.60705@codemonkey.ws> (raw)
In-Reply-To: <4BB206EF.3030100@collabora.co.uk>

On 03/30/2010 09:13 AM, Ian Molton wrote:
>
> > From 5f484301d73fa53009bbcd430f8ae85868b67772 Mon Sep 17 00:00:00 2001
> From: Ian Molton<ian.molton@collabora.co.uk>
> Date: Tue, 17 Nov 2009 14:34:12 +0000
> Subject: [PATCH 2/4] virtio: Add virtio-rng driver
>
> 	This patch adds support for virtio-rng. Data is read from a chardev and
> can be either raw entropy or received via the EGD protocol.
>
> Signed-off-by: Ian Molton<ian.molton@collabora.co.uk>
>    

Hi Ian,

A couple review comments below.  I've read the thread.  virtio-rng 
should stand on it's own as it's a spec'd out virtio device so I'm with 
you there.

The SIZE qdev patch can't be applied until there's a consumer of it.  
I've already expressed my opinion about the socket reconnect patch.  I 
don't think it's the right functionality for qemu to implement because 
the semantics concern me.  Really, a more thorough refactoring of 
CharDrivers is needed such that it supported connected and disconnected 
states along with QMP events for the transitions.

I agree with Paul that the EGD logic ought to be separated.  It probably 
makes sense to modify this a bit to have a split front-end/back-end.  
For instance:

-device virtio-rng-pci,rngdev=foo -rngdev egd,addr=unix:/path/to/rng,id=foo

You could also have a syntax helper like:

-rng egd,addr:/path/to/rng

See the recent virtfs patch series for an example of this.

With those changes, I'd happily apply this series.

> ---
>   Makefile.target |    2 +-
>   hw/pci.h        |    1 +
>   hw/virtio-pci.c |   29 ++++++++
>   hw/virtio-rng.c |  195
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/virtio-rng.h |   19 ++++++
>   hw/virtio.h     |    2 +
>   rng.h           |   14 ++++
>   7 files changed, 261 insertions(+), 1 deletions(-)
>   create mode 100644 hw/virtio-rng.c
>   create mode 100644 hw/virtio-rng.h
>   create mode 100644 rng.h
>
> diff --git a/Makefile.target b/Makefile.target
> index 16ea443..2f9c929 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -166,7 +166,7 @@ obj-y += qemu-timer.o
>   # virtio has to be here due to weird dependency between PCI and virtio-net.
>   # need to fix this properly
>   obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
> -obj-y += rwhandler.o
> +obj-y += virtio-rng.o rwhandler.o
>   obj-$(CONFIG_KVM) += kvm.o kvm-all.o
>   LIBS+=-lz
>
> diff --git a/hw/pci.h b/hw/pci.h
> index 20c670e..dc61cb5 100644
> --- a/hw/pci.h
> +++ b/hw/pci.h
> @@ -69,6 +69,7 @@
>   #define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
>   #define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
>   #define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
> +#define PCI_DEVICE_ID_VIRTIO_RNG         0x1004
>
>   #define FMT_PCIBUS                      PRIx64
>
> diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
> index 6eb19cd..bee3105 100644
> --- a/hw/virtio-pci.c
> +++ b/hw/virtio-pci.c
> @@ -23,6 +23,7 @@
>   #include "msix.h"
>   #include "net.h"
>   #include "block_int.h"
> +#include "rng.h"
>   #include "loader.h"
>
>   /* from Linux's linux/virtio_pci.h */
> @@ -95,6 +96,7 @@ typedef struct {
>       uint32_t nvectors;
>       BlockConf block;
>       NICConf nic;
> +    RNGConf rng;
>       uint32_t host_features;
>       /* Max. number of ports we can have for a the virtio-serial device */
>       uint32_t max_virtserial_ports;
> @@ -552,6 +554,21 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
>       return 0;
>   }
>
> +static int virtio_rng_init_pci(PCIDevice *pci_dev)
> +{
> +    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
> +    VirtIODevice *vdev;
> +
> +    vdev = virtio_rng_init(&pci_dev->qdev,&proxy->rng);
> +    virtio_init_pci(proxy, vdev,
> +                    PCI_VENDOR_ID_REDHAT_QUMRANET,
> +                    PCI_DEVICE_ID_VIRTIO_RNG,
> +                    PCI_CLASS_OTHERS,
> +                    0x00);
> +
> +    return 0;
> +}
> +
>   static PCIDeviceInfo virtio_info[] = {
>       {
>           .qdev.name = "virtio-blk-pci",
> @@ -606,6 +623,18 @@ static PCIDeviceInfo virtio_info[] = {
>           },
>           .qdev.reset = virtio_pci_reset,
>       },{
> +        .qdev.name = "virtio-rng-pci",
> +        .qdev.size = sizeof(VirtIOPCIProxy),
> +        .init      = virtio_rng_init_pci,
> +        .exit      = virtio_exit_pci,
> +        .qdev.props = (Property[]) {
> +            DEFINE_PROP_CHR("chardev",     VirtIOPCIProxy, rng.chrdev),
> +            DEFINE_PROP_SIZE("rate",       VirtIOPCIProxy, rng.rate, 0),
> +            DEFINE_PROP_STRING("protocol", VirtIOPCIProxy, rng.proto),
> +            DEFINE_PROP_END_OF_LIST(),
> +        },
> +        .qdev.reset = virtio_pci_reset,
> +    },{
>           /* end of list */
>       }
>   };
> diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
> new file mode 100644
> index 0000000..154ea76
> --- /dev/null
> +++ b/hw/virtio-rng.c
> @@ -0,0 +1,195 @@
> +/*
> + * Virtio RNG Device
> + *
> + * Copyright Collabora 2009
> + *
> + * Authors:
> + *  Ian Molton<ian.molton@collabora.co.uk>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "hw.h"
> +#include "qemu-char.h"
> +#include "virtio.h"
> +#include "virtio-rng.h"
> +#include "rng.h"
> +#include<sys/time.h>
> +
> +typedef struct VirtIORng
> +{
> +    VirtIODevice vdev;
> +    VirtQueue *vq;
> +    CharDriverState *chr;
> +    struct timeval last;
> +    int rate;
> +    int egd;
> +    int entropy_remaining;
> +    int pool;
> +} VirtIORng;
> +
> +/* Maximum size of the buffer the guest expects */
> +#define BUFF_MAX 64
> +
> +/* EGD protocol - we only use this command */
> +#define EGD_READ_BLOCK 0x2
> +
> +#define EGD_MAX_BLOCK_SIZE 255
> +#define EGD_MAX_REQUESTS 3
> +#define EGD_MAX_POOL_SIZE (EGD_MAX_BLOCK_SIZE * (EGD_MAX_REQUESTS-1))
> +
> +static inline void req_entropy(VirtIORng *s)
> +{
> +    static const unsigned char entropy_rq[2] = { EGD_READ_BLOCK,
> +                                                 EGD_MAX_BLOCK_SIZE };
> +    if (s->egd) {
> +        /* Let the socket buffer up the incoming data for us. Max block
> size
> +           for EGD protocol is (stupidly) 255, so make sure we always
> have a
> +           block pending for performance. We can have 3 outstanding
> buffers */
>    

Whitespace damaged (broken mailer?).

> +        if (s->pool<= EGD_MAX_POOL_SIZE) {
> +            s->chr->chr_write(s->chr, entropy_rq, sizeof(entropy_rq));
> +            s->pool += EGD_MAX_BLOCK_SIZE;
> +        }
> +    } else {
> +        s->pool = BUFF_MAX;
> +    }
> +}
> +
> +static int vrng_can_read(void *opaque)
> +{
> +    VirtIORng *s = (VirtIORng *) opaque;
> +    struct timeval now, d;
> +    int max_entropy;
> +
> +    if (!virtio_queue_ready(s->vq) ||
> +        !(s->vdev.status&  VIRTIO_CONFIG_S_DRIVER_OK) ||
> +        virtio_queue_empty(s->vq))
> +        return 0;
>    

Missing braces (CODING_STYLE).

> +    req_entropy(s);
> +
> +    if (s->rate) {
> +        qemu_gettimeofday(&now);
> +        timersub(&now,&s->last,&d);
> +        if (d.tv_sec * 1000000 + d.tv_usec>  1000000) {
> +            s->entropy_remaining = s->rate;
> +            s->last = now;
> +        }
>    

Should be based on rt_clock

> +        max_entropy = MIN(s->pool, s->entropy_remaining);
> +    } else {
> +        max_entropy = s->pool;
> +    }
> +
> +    /* current implementations have a 64 byte buffer.
> +     * We fall back to a one byte per read if there is not enough room.
> +     */
> +    max_entropy = MIN(max_entropy, BUFF_MAX);
> +    if (max_entropy) {
> +        if (virtqueue_avail_bytes(s->vq, max_entropy, 0))
> +            return max_entropy;
> +        if (virtqueue_avail_bytes(s->vq, 1, 0))
> +            return 1;
>    

Missing braces (CODING_STYLE).

> +    }
> +    return 0;
> +}
> +
> +static void vrng_read(void *opaque, const uint8_t *buf, int size)
> +{
> +    VirtIORng *s = (VirtIORng *) opaque;
> +    VirtQueueElement elem;
> +    int offset = 0;
> +
> +    /* The current kernel implementation has only one outstanding input
> +     * buffer of 64 bytes.
> +     */
> +    while (offset<  size) {
> +        int i = 0;
> +        if (!virtqueue_pop(s->vq,&elem))
> +                break;
>    

Braces.

> +        while (offset<  size&&  i<  elem.in_num) {
> +            int len = MIN(elem.in_sg[i].iov_len, size - offset);
> +            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
> +            offset += len;
> +            i++;
> +        }
> +        virtqueue_push(s->vq,&elem, size);
> +    }
> +
> +    if (s->rate)
> +        s->entropy_remaining -= size;
>    

Braces (lots more too).

> +    s->pool -= size;
> +
> +    virtio_notify(&s->vdev, s->vq);
> +}
> +
> +static void vrng_event(void *opaque, int event)
> +{
> +
> +}
> +
> +
> +
> +static void virtio_rng_handle(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    /* Nothing to do - we push data when its available */
> +}
> +
> +static uint32_t virtio_rng_get_features(VirtIODevice *vdev, uint32_t
> features)
> +{
> +    return 0;
> +}
> +
> +static void virtio_rng_save(QEMUFile *f, void *opaque)
> +{
> +    VirtIORng *s = opaque;
> +
> +    virtio_save(&s->vdev, f);
> +}
> +
> +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
> +{
> +    VirtIORng *s = opaque;
> +
> +    if (version_id != 1)
> +        return -EINVAL;
> +
> +    virtio_load(&s->vdev, f);
> +    return 0;
> +}
> +
> +VirtIODevice *virtio_rng_init(DeviceState *dev, RNGConf *rngdev)
> +{
> +    VirtIORng *s;
> +    s = (VirtIORng *)virtio_common_init("virtio-rng",
> +                                            VIRTIO_ID_RNG,
> +                                            0, sizeof(VirtIORng));
> +
> +    if (!s)
> +        return NULL;
> +
> +    s->vdev.get_features = virtio_rng_get_features;
> +
> +    s->vq = virtio_add_queue(&s->vdev, 128, virtio_rng_handle);
> +    s->chr = rngdev->chrdev;
> +    s->rate = rngdev->rate;
> +    gettimeofday(&s->last, NULL);
> +
> +    if(rngdev->proto&&  !strncmp(rngdev->proto, "egd", 3))
> +        s->egd = 1;
> +
> +#ifdef DEBUG
>    

It's more typical to introduce a debugging macro (like dprintf()) and 
then have a single define at the top of the file to enable the macro.

This will make conversion to a more unified logging mechanism a lot 
easier down the road.

Regards,

Anthony Liguori

> +    printf("entropy being read from %s", rngdev->chrdev->label);
> +    if(s->rate)
> +        printf(" at %d bytes/sec max.", s->rate);
> +    printf(" protocol: %s\n", s->egd?"egd":"raw");
> +#endif
> +
> +    qemu_chr_add_handlers(s->chr, vrng_can_read, vrng_read, vrng_event, s);
> +
> +    register_savevm("virtio-rng", -1, 1, virtio_rng_save,
> virtio_rng_load, s);
> +
> +    return&s->vdev;
> +}
> +
> diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
> new file mode 100644
> index 0000000..bc4d2d8
> --- /dev/null
> +++ b/hw/virtio-rng.h
> @@ -0,0 +1,19 @@
> +/*
> + * Virtio RNG Support
> + *
> + * Copyright Collabora 2009
> + *
> + * Authors:
> + *  Ian Molton<ian.molton@collabora.co.uk>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +#ifndef _QEMU_VIRTIO_RNG_H
> +#define _QEMU_VIRTIO_RNG_H
> +
> +/* The ID for virtio console */
> +#define VIRTIO_ID_RNG 4
> +
> +#endif
> diff --git a/hw/virtio.h b/hw/virtio.h
> index 3baa2a3..749b2a6 100644
> --- a/hw/virtio.h
> +++ b/hw/virtio.h
> @@ -16,6 +16,7 @@
>
>   #include "hw.h"
>   #include "net.h"
> +#include "rng.h"
>   #include "qdev.h"
>   #include "sysemu.h"
>   #include "block_int.h"
> @@ -174,6 +175,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev,
> BlockConf *conf);
>   VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
>   VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
>   VirtIODevice *virtio_balloon_init(DeviceState *dev);
> +VirtIODevice *virtio_rng_init(DeviceState *dev, RNGConf *rngdev);
>
>   void virtio_net_exit(VirtIODevice *vdev);
>
> diff --git a/rng.h b/rng.h
> new file mode 100644
> index 0000000..14ae7e0
> --- /dev/null
> +++ b/rng.h
> @@ -0,0 +1,14 @@
> +#ifndef QEMU_RNG_H
> +#define QEMU_RNG_H
> +
> +#include "qemu-option.h"
> +
> +/* qdev rng properties */
> +
> +typedef struct RNGConf {
> +    CharDriverState *chrdev;
> +    uint64_t rate;
> +    char *proto;
> +} RNGConf;
> +
> +#endif
>    

      parent reply	other threads:[~2010-05-03 18:25 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-30 14:05 [Qemu-devel] [PATCH 0/2] VirtIO RNG Ian Molton
2010-03-30 14:12 ` [Qemu-devel] [PATCH 1/2] " Ian Molton
2010-03-30 14:13 ` [Qemu-devel] [PATCH 2/2] " Ian Molton
2010-04-01 12:17   ` Paul Brook
2010-04-01 12:30     ` Jamie Lokier
2010-04-01 14:03       ` Paul Brook
2010-04-02 10:13         ` Ian Molton
2010-04-03 15:06           ` Paul Brook
2010-04-13 14:41             ` Ian Molton
2010-04-13 15:01               ` Paul Brook
2010-04-13 15:32               ` Paul Brook
2010-04-20 15:15                 ` Ian Molton
2010-04-20 16:13                   ` Jamie Lokier
2010-04-20 19:52                     ` Ian Molton
2010-04-20 20:11                       ` Blue Swirl
2010-04-20 20:56                       ` Jamie Lokier
2010-04-20 21:31                         ` Ian Molton
2010-04-20 21:55                           ` Jamie Lokier
2010-04-21  7:43                           ` Gerd Hoffmann
2010-04-21  9:40                             ` Jamie Lokier
2010-04-21 12:34                               ` Ian Molton
2010-04-21 13:55                                 ` Gerd Hoffmann
2010-04-22 19:06                                   ` Ian Molton
2010-04-22 21:05                                     ` Jamie Lokier
2010-04-23 10:17                                       ` Ian Molton
2010-04-24  1:37                                         ` Jamie Lokier
2010-04-24  8:58                                           ` Ian Molton
2010-04-23  8:27                                     ` Gerd Hoffmann
2010-04-23  9:28                                       ` Ian Molton
2010-04-23 14:07                                         ` Gerd Hoffmann
2010-04-23 15:49                                           ` Ian Molton
2010-04-23 17:32                                             ` Jamie Lokier
2010-04-24  9:16                                               ` Ian Molton
2010-04-02 10:15       ` Ian Molton
2010-04-02 10:07     ` Ian Molton
2010-05-03 17:56   ` Anthony Liguori [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4BDF0E56.60705@codemonkey.ws \
    --to=anthony@codemonkey.ws \
    --cc=ian.molton@collabora.co.uk \
    --cc=kraxel@redhat.com \
    --cc=paul@codesourcery.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).