1 /* 2 * Vhost-user RNG virtio device 3 * 4 * Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org> 5 * 6 * Implementation seriously tailored on vhost-user-i2c.c 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 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" 18 19 static const int feature_bits[] = { 20 VIRTIO_F_RING_RESET, 21 VHOST_INVALID_FEATURE_BIT 22 }; 23 24 static void vu_rng_start(VirtIODevice *vdev) 25 { 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); 29 int ret; 30 int i; 31 32 if (!k->set_guest_notifiers) { 33 error_report("binding does not support guest notifiers"); 34 return; 35 } 36 37 ret = vhost_dev_enable_notifiers(&rng->vhost_dev, vdev); 38 if (ret < 0) { 39 error_report("Error enabling host notifiers: %d", -ret); 40 return; 41 } 42 43 ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, true); 44 if (ret < 0) { 45 error_report("Error binding guest notifier: %d", -ret); 46 goto err_host_notifiers; 47 } 48 49 rng->vhost_dev.acked_features = vdev->guest_features; 50 ret = vhost_dev_start(&rng->vhost_dev, vdev, true); 51 if (ret < 0) { 52 error_report("Error starting vhost-user-rng: %d", -ret); 53 goto err_guest_notifiers; 54 } 55 56 /* 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. 60 */ 61 for (i = 0; i < rng->vhost_dev.nvqs; i++) { 62 vhost_virtqueue_mask(&rng->vhost_dev, vdev, i, false); 63 } 64 65 return; 66 67 err_guest_notifiers: 68 k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false); 69 err_host_notifiers: 70 vhost_dev_disable_notifiers(&rng->vhost_dev, vdev); 71 } 72 73 static void vu_rng_stop(VirtIODevice *vdev) 74 { 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); 78 int ret; 79 80 if (!k->set_guest_notifiers) { 81 return; 82 } 83 84 vhost_dev_stop(&rng->vhost_dev, vdev, true); 85 86 ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false); 87 if (ret < 0) { 88 error_report("vhost guest notifier cleanup failed: %d", ret); 89 return; 90 } 91 92 vhost_dev_disable_notifiers(&rng->vhost_dev, vdev); 93 } 94 95 static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status) 96 { 97 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 98 bool should_start = virtio_device_should_start(vdev, status); 99 100 if (vhost_dev_is_started(&rng->vhost_dev) == should_start) { 101 return; 102 } 103 104 if (should_start) { 105 vu_rng_start(vdev); 106 } else { 107 vu_rng_stop(vdev); 108 } 109 } 110 111 static uint64_t vu_rng_get_features(VirtIODevice *vdev, 112 uint64_t requested_features, Error **errp) 113 { 114 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 115 116 return vhost_get_features(&rng->vhost_dev, feature_bits, 117 requested_features); 118 } 119 120 static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq) 121 { 122 /* 123 * Not normally called; it's the daemon that handles the queue; 124 * however virtio's cleanup path can call this. 125 */ 126 } 127 128 static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) 129 { 130 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 131 132 vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); 133 } 134 135 static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx) 136 { 137 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 138 139 return vhost_virtqueue_pending(&rng->vhost_dev, idx); 140 } 141 142 static void vu_rng_connect(DeviceState *dev) 143 { 144 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 145 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 146 147 if (rng->connected) { 148 return; 149 } 150 151 rng->connected = true; 152 153 /* restore vhost state */ 154 if (virtio_device_started(vdev, vdev->status)) { 155 vu_rng_start(vdev); 156 } 157 } 158 159 static void vu_rng_disconnect(DeviceState *dev) 160 { 161 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 162 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 163 164 if (!rng->connected) { 165 return; 166 } 167 168 rng->connected = false; 169 170 if (vhost_dev_is_started(&rng->vhost_dev)) { 171 vu_rng_stop(vdev); 172 } 173 } 174 175 static void vu_rng_event(void *opaque, QEMUChrEvent event) 176 { 177 DeviceState *dev = opaque; 178 179 switch (event) { 180 case CHR_EVENT_OPENED: 181 vu_rng_connect(dev); 182 break; 183 case CHR_EVENT_CLOSED: 184 vu_rng_disconnect(dev); 185 break; 186 case CHR_EVENT_BREAK: 187 case CHR_EVENT_MUX_IN: 188 case CHR_EVENT_MUX_OUT: 189 /* Ignore */ 190 break; 191 } 192 } 193 194 static void vu_rng_device_realize(DeviceState *dev, Error **errp) 195 { 196 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 197 VHostUserRNG *rng = VHOST_USER_RNG(dev); 198 int ret; 199 200 if (!rng->chardev.chr) { 201 error_setg(errp, "missing chardev"); 202 return; 203 } 204 205 if (!vhost_user_init(&rng->vhost_user, &rng->chardev, errp)) { 206 return; 207 } 208 209 virtio_init(vdev, VIRTIO_ID_RNG, 0); 210 211 rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output); 212 if (!rng->req_vq) { 213 error_setg_errno(errp, -1, "virtio_add_queue() failed"); 214 goto virtio_add_queue_failed; 215 } 216 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); 221 if (ret < 0) { 222 error_setg_errno(errp, -ret, "vhost_dev_init() failed"); 223 goto vhost_dev_init_failed; 224 } 225 226 qemu_chr_fe_set_handlers(&rng->chardev, NULL, NULL, vu_rng_event, NULL, 227 dev, NULL, true); 228 229 return; 230 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); 237 } 238 239 static void vu_rng_device_unrealize(DeviceState *dev) 240 { 241 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 242 VHostUserRNG *rng = VHOST_USER_RNG(dev); 243 struct vhost_virtqueue *vhost_vqs = rng->vhost_dev.vqs; 244 245 vu_rng_set_status(vdev, 0); 246 247 vhost_dev_cleanup(&rng->vhost_dev); 248 g_free(vhost_vqs); 249 virtio_delete_queue(rng->req_vq); 250 virtio_cleanup(vdev); 251 vhost_user_cleanup(&rng->vhost_user); 252 } 253 254 static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) 255 { 256 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 257 return &rng->vhost_dev; 258 } 259 260 static const VMStateDescription vu_rng_vmstate = { 261 .name = "vhost-user-rng", 262 .unmigratable = 1, 263 }; 264 265 static Property vu_rng_properties[] = { 266 DEFINE_PROP_CHR("chardev", VHostUserRNG, chardev), 267 DEFINE_PROP_END_OF_LIST(), 268 }; 269 270 static void vu_rng_class_init(ObjectClass *klass, void *data) 271 { 272 DeviceClass *dc = DEVICE_CLASS(klass); 273 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 274 275 device_class_set_props(dc, vu_rng_properties); 276 dc->vmsd = &vu_rng_vmstate; 277 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 278 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; 286 } 287 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, 293 }; 294 295 static void vu_rng_register_types(void) 296 { 297 type_register_static(&vu_rng_info); 298 } 299 300 type_init(vu_rng_register_types) 301