diff options
Diffstat (limited to 'hw/virtio-rng.c')
-rw-r--r-- | hw/virtio-rng.c | 205 |
1 files changed, 0 insertions, 205 deletions
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c deleted file mode 100644 index a73ef8e33..000000000 --- a/hw/virtio-rng.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * A virtio device implementing a hardware random number generator. - * - * Copyright 2012 Red Hat, Inc. - * Copyright 2012 Amit Shah <amit.shah@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include "iov.h" -#include "qdev.h" -#include "virtio.h" -#include "virtio-rng.h" -#include "qemu/rng.h" - -typedef struct VirtIORNG { - VirtIODevice vdev; - - DeviceState *qdev; - - /* Only one vq - guest puts buffer(s) on it when it needs entropy */ - VirtQueue *vq; - - VirtIORNGConf *conf; - - RngBackend *rng; - - /* We purposefully don't migrate this state. The quota will reset on the - * destination as a result. Rate limiting is host state, not guest state. - */ - QEMUTimer *rate_limit_timer; - int64_t quota_remaining; -} VirtIORNG; - -static bool is_guest_ready(VirtIORNG *vrng) -{ - if (virtio_queue_ready(vrng->vq) - && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { - return true; - } - return false; -} - -static size_t get_request_size(VirtQueue *vq, unsigned quota) -{ - unsigned int in, out; - - virtqueue_get_avail_bytes(vq, &in, &out, quota, 0); - return in; -} - -static void virtio_rng_process(VirtIORNG *vrng); - -/* Send data from a char device over to the guest */ -static void chr_read(void *opaque, const void *buf, size_t size) -{ - VirtIORNG *vrng = opaque; - VirtQueueElement elem; - size_t len; - int offset; - - if (!is_guest_ready(vrng)) { - return; - } - - vrng->quota_remaining -= size; - - offset = 0; - while (offset < size) { - if (!virtqueue_pop(vrng->vq, &elem)) { - break; - } - len = iov_from_buf(elem.in_sg, elem.in_num, - 0, buf + offset, size - offset); - offset += len; - - virtqueue_push(vrng->vq, &elem, len); - } - virtio_notify(&vrng->vdev, vrng->vq); -} - -static void virtio_rng_process(VirtIORNG *vrng) -{ - size_t size; - unsigned quota; - - if (!is_guest_ready(vrng)) { - return; - } - - if (vrng->quota_remaining < 0) { - quota = 0; - } else { - quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX); - } - size = get_request_size(vrng->vq, quota); - size = MIN(vrng->quota_remaining, size); - if (size) { - rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); - } -} - -static void handle_input(VirtIODevice *vdev, VirtQueue *vq) -{ - VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); - virtio_rng_process(vrng); -} - -static uint32_t get_features(VirtIODevice *vdev, uint32_t f) -{ - return f; -} - -static void virtio_rng_save(QEMUFile *f, void *opaque) -{ - VirtIORNG *vrng = opaque; - - virtio_save(&vrng->vdev, f); -} - -static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) -{ - VirtIORNG *vrng = opaque; - - if (version_id != 1) { - return -EINVAL; - } - virtio_load(&vrng->vdev, f); - - /* We may have an element ready but couldn't process it due to a quota - * limit. Make sure to try again after live migration when the quota may - * have been reset. - */ - virtio_rng_process(vrng); - - return 0; -} - -static void check_rate_limit(void *opaque) -{ - VirtIORNG *s = opaque; - - s->quota_remaining = s->conf->max_bytes; - virtio_rng_process(s); - qemu_mod_timer(s->rate_limit_timer, - qemu_get_clock_ms(vm_clock) + s->conf->period_ms); -} - - -VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf) -{ - VirtIORNG *vrng; - VirtIODevice *vdev; - Error *local_err = NULL; - - vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, - sizeof(VirtIORNG)); - - vrng = DO_UPCAST(VirtIORNG, vdev, vdev); - - vrng->rng = conf->rng; - if (vrng->rng == NULL) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object"); - return NULL; - } - - rng_backend_open(vrng->rng, &local_err); - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return NULL; - } - - vrng->vq = virtio_add_queue(vdev, 8, handle_input); - vrng->vdev.get_features = get_features; - - vrng->qdev = dev; - vrng->conf = conf; - - assert(vrng->conf->max_bytes <= INT64_MAX); - vrng->quota_remaining = vrng->conf->max_bytes; - - vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock, - check_rate_limit, vrng); - - qemu_mod_timer(vrng->rate_limit_timer, - qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms); - - register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, - virtio_rng_load, vrng); - - return vdev; -} - -void virtio_rng_exit(VirtIODevice *vdev) -{ - VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); - - qemu_del_timer(vrng->rate_limit_timer); - qemu_free_timer(vrng->rate_limit_timer); - unregister_savevm(vrng->qdev, "virtio-rng", vrng); - virtio_cleanup(vdev); -} |