qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

virtio-rng.c (8135B)


      1 /*
      2  * A virtio device implementing a hardware random number generator.
      3  *
      4  * Copyright 2012 Red Hat, Inc.
      5  * Copyright 2012 Amit Shah <amit.shah@redhat.com>
      6  *
      7  * This work is licensed under the terms of the GNU GPL, version 2 or
      8  * (at your option) any later version.  See the COPYING file in the
      9  * top-level directory.
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "qapi/error.h"
     14 #include "qemu/iov.h"
     15 #include "qemu/module.h"
     16 #include "qemu/timer.h"
     17 #include "hw/virtio/virtio.h"
     18 #include "hw/qdev-properties.h"
     19 #include "hw/virtio/virtio-rng.h"
     20 #include "sysemu/rng.h"
     21 #include "sysemu/runstate.h"
     22 #include "qom/object_interfaces.h"
     23 #include "trace.h"
     24 
     25 static bool is_guest_ready(VirtIORNG *vrng)
     26 {
     27     VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
     28     if (virtio_queue_ready(vrng->vq)
     29         && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
     30         return true;
     31     }
     32     trace_virtio_rng_guest_not_ready(vrng);
     33     return false;
     34 }
     35 
     36 static size_t get_request_size(VirtQueue *vq, unsigned quota)
     37 {
     38     unsigned int in, out;
     39 
     40     virtqueue_get_avail_bytes(vq, &in, &out, quota, 0);
     41     return in;
     42 }
     43 
     44 static void virtio_rng_process(VirtIORNG *vrng);
     45 
     46 /* Send data from a char device over to the guest */
     47 static void chr_read(void *opaque, const void *buf, size_t size)
     48 {
     49     VirtIORNG *vrng = opaque;
     50     VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
     51     VirtQueueElement *elem;
     52     size_t len;
     53     int offset;
     54 
     55     if (!is_guest_ready(vrng)) {
     56         return;
     57     }
     58 
     59     /* we can't modify the virtqueue until
     60      * our state is fully synced
     61      */
     62 
     63     if (!runstate_check(RUN_STATE_RUNNING)) {
     64         trace_virtio_rng_cpu_is_stopped(vrng, size);
     65         return;
     66     }
     67 
     68     vrng->quota_remaining -= size;
     69 
     70     offset = 0;
     71     while (offset < size) {
     72         elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement));
     73         if (!elem) {
     74             break;
     75         }
     76         trace_virtio_rng_popped(vrng);
     77         len = iov_from_buf(elem->in_sg, elem->in_num,
     78                            0, buf + offset, size - offset);
     79         offset += len;
     80 
     81         virtqueue_push(vrng->vq, elem, len);
     82         trace_virtio_rng_pushed(vrng, len);
     83         g_free(elem);
     84     }
     85     virtio_notify(vdev, vrng->vq);
     86 
     87     if (!virtio_queue_empty(vrng->vq)) {
     88         /* If we didn't drain the queue, call virtio_rng_process
     89          * to take care of asking for more data as appropriate.
     90          */
     91         virtio_rng_process(vrng);
     92     }
     93 }
     94 
     95 static void virtio_rng_process(VirtIORNG *vrng)
     96 {
     97     size_t size;
     98     unsigned quota;
     99 
    100     if (!is_guest_ready(vrng)) {
    101         return;
    102     }
    103 
    104     if (vrng->activate_timer) {
    105         timer_mod(vrng->rate_limit_timer,
    106                   qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms);
    107         vrng->activate_timer = false;
    108     }
    109 
    110     if (vrng->quota_remaining < 0) {
    111         quota = 0;
    112     } else {
    113         quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
    114     }
    115     size = get_request_size(vrng->vq, quota);
    116 
    117     trace_virtio_rng_request(vrng, size, quota);
    118 
    119     size = MIN(vrng->quota_remaining, size);
    120     if (size) {
    121         rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
    122     }
    123 }
    124 
    125 static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
    126 {
    127     VirtIORNG *vrng = VIRTIO_RNG(vdev);
    128     virtio_rng_process(vrng);
    129 }
    130 
    131 static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
    132 {
    133     return f;
    134 }
    135 
    136 static void virtio_rng_vm_state_change(void *opaque, bool running,
    137                                        RunState state)
    138 {
    139     VirtIORNG *vrng = opaque;
    140 
    141     trace_virtio_rng_vm_state_change(vrng, running, state);
    142 
    143     /* We may have an element ready but couldn't process it due to a quota
    144      * limit or because CPU was stopped.  Make sure to try again when the
    145      * CPU restart.
    146      */
    147 
    148     if (running && is_guest_ready(vrng)) {
    149         virtio_rng_process(vrng);
    150     }
    151 }
    152 
    153 static void check_rate_limit(void *opaque)
    154 {
    155     VirtIORNG *vrng = opaque;
    156 
    157     vrng->quota_remaining = vrng->conf.max_bytes;
    158     virtio_rng_process(vrng);
    159     vrng->activate_timer = true;
    160 }
    161 
    162 static void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status)
    163 {
    164     VirtIORNG *vrng = VIRTIO_RNG(vdev);
    165 
    166     if (!vdev->vm_running) {
    167         return;
    168     }
    169     vdev->status = status;
    170 
    171     /* Something changed, try to process buffers */
    172     virtio_rng_process(vrng);
    173 }
    174 
    175 static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
    176 {
    177     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    178     VirtIORNG *vrng = VIRTIO_RNG(dev);
    179 
    180     if (vrng->conf.period_ms <= 0) {
    181         error_setg(errp, "'period' parameter expects a positive integer");
    182         return;
    183     }
    184 
    185     /* Workaround: Property parsing does not enforce unsigned integers,
    186      * So this is a hack to reject such numbers. */
    187     if (vrng->conf.max_bytes > INT64_MAX) {
    188         error_setg(errp, "'max-bytes' parameter must be non-negative, "
    189                    "and less than 2^63");
    190         return;
    191     }
    192 
    193     if (vrng->conf.rng == NULL) {
    194         Object *default_backend = object_new(TYPE_RNG_BUILTIN);
    195 
    196         if (!user_creatable_complete(USER_CREATABLE(default_backend),
    197                                      errp)) {
    198             object_unref(default_backend);
    199             return;
    200         }
    201 
    202         object_property_add_child(OBJECT(dev), "default-backend",
    203                                   default_backend);
    204 
    205         /* The child property took a reference, we can safely drop ours now */
    206         object_unref(default_backend);
    207 
    208         object_property_set_link(OBJECT(dev), "rng", default_backend,
    209                                  &error_abort);
    210     }
    211 
    212     vrng->rng = vrng->conf.rng;
    213     if (vrng->rng == NULL) {
    214         error_setg(errp, "'rng' parameter expects a valid object");
    215         return;
    216     }
    217 
    218     virtio_init(vdev, VIRTIO_ID_RNG, 0);
    219 
    220     vrng->vq = virtio_add_queue(vdev, 8, handle_input);
    221     vrng->quota_remaining = vrng->conf.max_bytes;
    222     vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
    223                                                check_rate_limit, vrng);
    224     vrng->activate_timer = true;
    225 
    226     vrng->vmstate = qemu_add_vm_change_state_handler(virtio_rng_vm_state_change,
    227                                                      vrng);
    228 }
    229 
    230 static void virtio_rng_device_unrealize(DeviceState *dev)
    231 {
    232     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    233     VirtIORNG *vrng = VIRTIO_RNG(dev);
    234 
    235     qemu_del_vm_change_state_handler(vrng->vmstate);
    236     timer_free(vrng->rate_limit_timer);
    237     virtio_del_queue(vdev, 0);
    238     virtio_cleanup(vdev);
    239 }
    240 
    241 static const VMStateDescription vmstate_virtio_rng = {
    242     .name = "virtio-rng",
    243     .minimum_version_id = 1,
    244     .version_id = 1,
    245     .fields = (VMStateField[]) {
    246         VMSTATE_VIRTIO_DEVICE,
    247         VMSTATE_END_OF_LIST()
    248     },
    249 };
    250 
    251 static Property virtio_rng_properties[] = {
    252     /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
    253      * you have an entropy source capable of generating more entropy than this
    254      * and you can pass it through via virtio-rng, then hats off to you.  Until
    255      * then, this is unlimited for all practical purposes.
    256      */
    257     DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
    258     DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
    259     DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *),
    260     DEFINE_PROP_END_OF_LIST(),
    261 };
    262 
    263 static void virtio_rng_class_init(ObjectClass *klass, void *data)
    264 {
    265     DeviceClass *dc = DEVICE_CLASS(klass);
    266     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    267 
    268     device_class_set_props(dc, virtio_rng_properties);
    269     dc->vmsd = &vmstate_virtio_rng;
    270     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    271     vdc->realize = virtio_rng_device_realize;
    272     vdc->unrealize = virtio_rng_device_unrealize;
    273     vdc->get_features = get_features;
    274     vdc->set_status = virtio_rng_set_status;
    275 }
    276 
    277 static const TypeInfo virtio_rng_info = {
    278     .name = TYPE_VIRTIO_RNG,
    279     .parent = TYPE_VIRTIO_DEVICE,
    280     .instance_size = sizeof(VirtIORNG),
    281     .class_init = virtio_rng_class_init,
    282 };
    283 
    284 static void virtio_register_types(void)
    285 {
    286     type_register_static(&virtio_rng_info);
    287 }
    288 
    289 type_init(virtio_register_types)