*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu/iov.h"
#include "hw/qdev.h"
#include "hw/virtio/virtio.h"
{
VirtIORNG *vrng = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
size_t len;
int offset;
return;
}
+ /* we can't modify the virtqueue until
+ * our state is fully synced
+ */
+
+ if (!runstate_check(RUN_STATE_RUNNING)) {
+ trace_virtio_rng_cpu_is_stopped(vrng, size);
+ return;
+ }
+
vrng->quota_remaining -= size;
offset = 0;
while (offset < size) {
- if (!virtqueue_pop(vrng->vq, &elem)) {
+ elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement));
+ if (!elem) {
break;
}
- len = iov_from_buf(elem.in_sg, elem.in_num,
+ trace_virtio_rng_popped(vrng);
+ len = iov_from_buf(elem->in_sg, elem->in_num,
0, buf + offset, size - offset);
offset += len;
- virtqueue_push(vrng->vq, &elem, len);
+ virtqueue_push(vrng->vq, elem, len);
trace_virtio_rng_pushed(vrng, len);
+ g_free(elem);
}
virtio_notify(vdev, vrng->vq);
+
+ if (!virtio_queue_empty(vrng->vq)) {
+ /* If we didn't drain the queue, call virtio_rng_process
+ * to take care of asking for more data as appropriate.
+ */
+ virtio_rng_process(vrng);
+ }
}
static void virtio_rng_process(VirtIORNG *vrng)
return f;
}
-static void virtio_rng_save(QEMUFile *f, void *opaque)
-{
- VirtIODevice *vdev = opaque;
-
- virtio_save(vdev, f);
-}
-
-static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
+static void virtio_rng_vm_state_change(void *opaque, int running,
+ RunState state)
{
VirtIORNG *vrng = opaque;
- int ret;
- if (version_id != 1) {
- return -EINVAL;
- }
- ret = virtio_load(VIRTIO_DEVICE(vrng), f, version_id);
- if (ret != 0) {
- return ret;
- }
+ trace_virtio_rng_vm_state_change(vrng, running, state);
/* 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.
+ * limit or because CPU was stopped. Make sure to try again when the
+ * CPU restart.
*/
- virtio_rng_process(vrng);
- return 0;
+ if (running && is_guest_ready(vrng)) {
+ virtio_rng_process(vrng);
+ }
}
static void check_rate_limit(void *opaque)
vrng->activate_timer = true;
}
+static void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIORNG *vrng = VIRTIO_RNG(vdev);
+
+ if (!vdev->vm_running) {
+ return;
+ }
+ vdev->status = status;
+
+ /* Something changed, try to process buffers */
+ virtio_rng_process(vrng);
+}
+
static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
if (vrng->conf.rng == NULL) {
vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
- user_creatable_complete(OBJECT(vrng->conf.default_backend),
+ user_creatable_complete(USER_CREATABLE(vrng->conf.default_backend),
&local_err);
if (local_err) {
error_propagate(errp, local_err);
vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
check_rate_limit, vrng);
vrng->activate_timer = true;
- register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
- virtio_rng_load, vrng);
+
+ vrng->vmstate = qemu_add_vm_change_state_handler(virtio_rng_vm_state_change,
+ vrng);
}
static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIORNG *vrng = VIRTIO_RNG(dev);
+ qemu_del_vm_change_state_handler(vrng->vmstate);
timer_del(vrng->rate_limit_timer);
timer_free(vrng->rate_limit_timer);
- unregister_savevm(dev, "virtio-rng", vrng);
virtio_cleanup(vdev);
}
+static const VMStateDescription vmstate_virtio_rng = {
+ .name = "virtio-rng",
+ .minimum_version_id = 1,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_VIRTIO_DEVICE,
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static Property virtio_rng_properties[] = {
/* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
* you have an entropy source capable of generating more entropy than this
*/
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
+ DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *),
DEFINE_PROP_END_OF_LIST(),
};
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
dc->props = virtio_rng_properties;
+ dc->vmsd = &vmstate_virtio_rng;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
vdc->realize = virtio_rng_device_realize;
vdc->unrealize = virtio_rng_device_unrealize;
vdc->get_features = get_features;
-}
-
-static void virtio_rng_initfn(Object *obj)
-{
- VirtIORNG *vrng = VIRTIO_RNG(obj);
-
- object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
- (Object **)&vrng->conf.rng,
- qdev_prop_allow_set_link_before_realize,
- OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
+ vdc->set_status = virtio_rng_set_status;
}
static const TypeInfo virtio_rng_info = {
.name = TYPE_VIRTIO_RNG,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIORNG),
- .instance_init = virtio_rng_initfn,
.class_init = virtio_rng_class_init,
};