2 * Vhost-user RNG virtio device
4 * Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org>
6 * Implementation seriously tailored on vhost-user-i2c.c
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
12 #include "qapi/error.h"
13 #include "hw/qdev-properties.h"
14 #include "hw/virtio/virtio-bus.h"
15 #include "hw/virtio/vhost-user-rng.h"
16 #include "qemu/error-report.h"
17 #include "standard-headers/linux/virtio_ids.h"
19 static const int feature_bits
[] = {
21 VHOST_INVALID_FEATURE_BIT
24 static void vu_rng_start(VirtIODevice
*vdev
)
26 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
27 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(vdev
)));
28 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
32 if (!k
->set_guest_notifiers
) {
33 error_report("binding does not support guest notifiers");
37 ret
= vhost_dev_enable_notifiers(&rng
->vhost_dev
, vdev
);
39 error_report("Error enabling host notifiers: %d", -ret
);
43 ret
= k
->set_guest_notifiers(qbus
->parent
, rng
->vhost_dev
.nvqs
, true);
45 error_report("Error binding guest notifier: %d", -ret
);
46 goto err_host_notifiers
;
49 rng
->vhost_dev
.acked_features
= vdev
->guest_features
;
50 ret
= vhost_dev_start(&rng
->vhost_dev
, vdev
, true);
52 error_report("Error starting vhost-user-rng: %d", -ret
);
53 goto err_guest_notifiers
;
57 * guest_notifier_mask/pending not used yet, so just unmask
58 * everything here. virtio-pci will do the right thing by
59 * enabling/disabling irqfd.
61 for (i
= 0; i
< rng
->vhost_dev
.nvqs
; i
++) {
62 vhost_virtqueue_mask(&rng
->vhost_dev
, vdev
, i
, false);
68 k
->set_guest_notifiers(qbus
->parent
, rng
->vhost_dev
.nvqs
, false);
70 vhost_dev_disable_notifiers(&rng
->vhost_dev
, vdev
);
73 static void vu_rng_stop(VirtIODevice
*vdev
)
75 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
76 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(vdev
)));
77 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
80 if (!k
->set_guest_notifiers
) {
84 vhost_dev_stop(&rng
->vhost_dev
, vdev
, true);
86 ret
= k
->set_guest_notifiers(qbus
->parent
, rng
->vhost_dev
.nvqs
, false);
88 error_report("vhost guest notifier cleanup failed: %d", ret
);
92 vhost_dev_disable_notifiers(&rng
->vhost_dev
, vdev
);
95 static void vu_rng_set_status(VirtIODevice
*vdev
, uint8_t status
)
97 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
98 bool should_start
= virtio_device_should_start(vdev
, status
);
100 if (vhost_dev_is_started(&rng
->vhost_dev
) == should_start
) {
111 static uint64_t vu_rng_get_features(VirtIODevice
*vdev
,
112 uint64_t requested_features
, Error
**errp
)
114 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
116 return vhost_get_features(&rng
->vhost_dev
, feature_bits
,
120 static void vu_rng_handle_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
123 * Not normally called; it's the daemon that handles the queue;
124 * however virtio's cleanup path can call this.
128 static void vu_rng_guest_notifier_mask(VirtIODevice
*vdev
, int idx
, bool mask
)
130 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
132 vhost_virtqueue_mask(&rng
->vhost_dev
, vdev
, idx
, mask
);
135 static bool vu_rng_guest_notifier_pending(VirtIODevice
*vdev
, int idx
)
137 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
139 return vhost_virtqueue_pending(&rng
->vhost_dev
, idx
);
142 static void vu_rng_connect(DeviceState
*dev
)
144 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
145 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
147 if (rng
->connected
) {
151 rng
->connected
= true;
153 /* restore vhost state */
154 if (virtio_device_started(vdev
, vdev
->status
)) {
159 static void vu_rng_disconnect(DeviceState
*dev
)
161 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
162 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
164 if (!rng
->connected
) {
168 rng
->connected
= false;
170 if (vhost_dev_is_started(&rng
->vhost_dev
)) {
175 static void vu_rng_event(void *opaque
, QEMUChrEvent event
)
177 DeviceState
*dev
= opaque
;
180 case CHR_EVENT_OPENED
:
183 case CHR_EVENT_CLOSED
:
184 vu_rng_disconnect(dev
);
186 case CHR_EVENT_BREAK
:
187 case CHR_EVENT_MUX_IN
:
188 case CHR_EVENT_MUX_OUT
:
194 static void vu_rng_device_realize(DeviceState
*dev
, Error
**errp
)
196 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
197 VHostUserRNG
*rng
= VHOST_USER_RNG(dev
);
200 if (!rng
->chardev
.chr
) {
201 error_setg(errp
, "missing chardev");
205 if (!vhost_user_init(&rng
->vhost_user
, &rng
->chardev
, errp
)) {
209 virtio_init(vdev
, VIRTIO_ID_RNG
, 0);
211 rng
->req_vq
= virtio_add_queue(vdev
, 4, vu_rng_handle_output
);
213 error_setg_errno(errp
, -1, "virtio_add_queue() failed");
214 goto virtio_add_queue_failed
;
217 rng
->vhost_dev
.nvqs
= 1;
218 rng
->vhost_dev
.vqs
= g_new0(struct vhost_virtqueue
, rng
->vhost_dev
.nvqs
);
219 ret
= vhost_dev_init(&rng
->vhost_dev
, &rng
->vhost_user
,
220 VHOST_BACKEND_TYPE_USER
, 0, errp
);
222 error_setg_errno(errp
, -ret
, "vhost_dev_init() failed");
223 goto vhost_dev_init_failed
;
226 qemu_chr_fe_set_handlers(&rng
->chardev
, NULL
, NULL
, vu_rng_event
, NULL
,
231 vhost_dev_init_failed
:
232 g_free(rng
->vhost_dev
.vqs
);
233 virtio_delete_queue(rng
->req_vq
);
234 virtio_add_queue_failed
:
235 virtio_cleanup(vdev
);
236 vhost_user_cleanup(&rng
->vhost_user
);
239 static void vu_rng_device_unrealize(DeviceState
*dev
)
241 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
242 VHostUserRNG
*rng
= VHOST_USER_RNG(dev
);
243 struct vhost_virtqueue
*vhost_vqs
= rng
->vhost_dev
.vqs
;
245 vu_rng_set_status(vdev
, 0);
247 vhost_dev_cleanup(&rng
->vhost_dev
);
249 virtio_delete_queue(rng
->req_vq
);
250 virtio_cleanup(vdev
);
251 vhost_user_cleanup(&rng
->vhost_user
);
254 static struct vhost_dev
*vu_rng_get_vhost(VirtIODevice
*vdev
)
256 VHostUserRNG
*rng
= VHOST_USER_RNG(vdev
);
257 return &rng
->vhost_dev
;
260 static const VMStateDescription vu_rng_vmstate
= {
261 .name
= "vhost-user-rng",
265 static Property vu_rng_properties
[] = {
266 DEFINE_PROP_CHR("chardev", VHostUserRNG
, chardev
),
267 DEFINE_PROP_END_OF_LIST(),
270 static void vu_rng_class_init(ObjectClass
*klass
, void *data
)
272 DeviceClass
*dc
= DEVICE_CLASS(klass
);
273 VirtioDeviceClass
*vdc
= VIRTIO_DEVICE_CLASS(klass
);
275 device_class_set_props(dc
, vu_rng_properties
);
276 dc
->vmsd
= &vu_rng_vmstate
;
277 set_bit(DEVICE_CATEGORY_INPUT
, dc
->categories
);
279 vdc
->realize
= vu_rng_device_realize
;
280 vdc
->unrealize
= vu_rng_device_unrealize
;
281 vdc
->get_features
= vu_rng_get_features
;
282 vdc
->set_status
= vu_rng_set_status
;
283 vdc
->guest_notifier_mask
= vu_rng_guest_notifier_mask
;
284 vdc
->guest_notifier_pending
= vu_rng_guest_notifier_pending
;
285 vdc
->get_vhost
= vu_rng_get_vhost
;
288 static const TypeInfo vu_rng_info
= {
289 .name
= TYPE_VHOST_USER_RNG
,
290 .parent
= TYPE_VIRTIO_DEVICE
,
291 .instance_size
= sizeof(VHostUserRNG
),
292 .class_init
= vu_rng_class_init
,
295 static void vu_rng_register_types(void)
297 type_register_static(&vu_rng_info
);
300 type_init(vu_rng_register_types
)