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 /* 133 * We don't support interrupts, return early if index is set to 134 * VIRTIO_CONFIG_IRQ_IDX. 135 */ 136 if (idx == VIRTIO_CONFIG_IRQ_IDX) { 137 return; 138 } 139 140 vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); 141 } 142 143 static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx) 144 { 145 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 146 147 /* 148 * We don't support interrupts, return early if index is set to 149 * VIRTIO_CONFIG_IRQ_IDX. 150 */ 151 if (idx == VIRTIO_CONFIG_IRQ_IDX) { 152 return false; 153 } 154 155 return vhost_virtqueue_pending(&rng->vhost_dev, idx); 156 } 157 158 static void vu_rng_connect(DeviceState *dev) 159 { 160 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 161 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 162 163 if (rng->connected) { 164 return; 165 } 166 167 rng->connected = true; 168 169 /* restore vhost state */ 170 if (virtio_device_started(vdev, vdev->status)) { 171 vu_rng_start(vdev); 172 } 173 } 174 175 static void vu_rng_disconnect(DeviceState *dev) 176 { 177 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 178 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 179 180 if (!rng->connected) { 181 return; 182 } 183 184 rng->connected = false; 185 186 if (vhost_dev_is_started(&rng->vhost_dev)) { 187 vu_rng_stop(vdev); 188 } 189 } 190 191 static void vu_rng_event(void *opaque, QEMUChrEvent event) 192 { 193 DeviceState *dev = opaque; 194 195 switch (event) { 196 case CHR_EVENT_OPENED: 197 vu_rng_connect(dev); 198 break; 199 case CHR_EVENT_CLOSED: 200 vu_rng_disconnect(dev); 201 break; 202 case CHR_EVENT_BREAK: 203 case CHR_EVENT_MUX_IN: 204 case CHR_EVENT_MUX_OUT: 205 /* Ignore */ 206 break; 207 } 208 } 209 210 static void vu_rng_device_realize(DeviceState *dev, Error **errp) 211 { 212 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 213 VHostUserRNG *rng = VHOST_USER_RNG(dev); 214 int ret; 215 216 if (!rng->chardev.chr) { 217 error_setg(errp, "missing chardev"); 218 return; 219 } 220 221 if (!vhost_user_init(&rng->vhost_user, &rng->chardev, errp)) { 222 return; 223 } 224 225 virtio_init(vdev, VIRTIO_ID_RNG, 0); 226 227 rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output); 228 if (!rng->req_vq) { 229 error_setg_errno(errp, -1, "virtio_add_queue() failed"); 230 goto virtio_add_queue_failed; 231 } 232 233 rng->vhost_dev.nvqs = 1; 234 rng->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rng->vhost_dev.nvqs); 235 ret = vhost_dev_init(&rng->vhost_dev, &rng->vhost_user, 236 VHOST_BACKEND_TYPE_USER, 0, errp); 237 if (ret < 0) { 238 error_setg_errno(errp, -ret, "vhost_dev_init() failed"); 239 goto vhost_dev_init_failed; 240 } 241 242 qemu_chr_fe_set_handlers(&rng->chardev, NULL, NULL, vu_rng_event, NULL, 243 dev, NULL, true); 244 245 return; 246 247 vhost_dev_init_failed: 248 g_free(rng->vhost_dev.vqs); 249 virtio_delete_queue(rng->req_vq); 250 virtio_add_queue_failed: 251 virtio_cleanup(vdev); 252 vhost_user_cleanup(&rng->vhost_user); 253 } 254 255 static void vu_rng_device_unrealize(DeviceState *dev) 256 { 257 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 258 VHostUserRNG *rng = VHOST_USER_RNG(dev); 259 struct vhost_virtqueue *vhost_vqs = rng->vhost_dev.vqs; 260 261 vu_rng_set_status(vdev, 0); 262 263 vhost_dev_cleanup(&rng->vhost_dev); 264 g_free(vhost_vqs); 265 virtio_delete_queue(rng->req_vq); 266 virtio_cleanup(vdev); 267 vhost_user_cleanup(&rng->vhost_user); 268 } 269 270 static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) 271 { 272 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 273 return &rng->vhost_dev; 274 } 275 276 static const VMStateDescription vu_rng_vmstate = { 277 .name = "vhost-user-rng", 278 .unmigratable = 1, 279 }; 280 281 static Property vu_rng_properties[] = { 282 DEFINE_PROP_CHR("chardev", VHostUserRNG, chardev), 283 DEFINE_PROP_END_OF_LIST(), 284 }; 285 286 static void vu_rng_class_init(ObjectClass *klass, void *data) 287 { 288 DeviceClass *dc = DEVICE_CLASS(klass); 289 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 290 291 device_class_set_props(dc, vu_rng_properties); 292 dc->vmsd = &vu_rng_vmstate; 293 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 294 295 vdc->realize = vu_rng_device_realize; 296 vdc->unrealize = vu_rng_device_unrealize; 297 vdc->get_features = vu_rng_get_features; 298 vdc->set_status = vu_rng_set_status; 299 vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; 300 vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; 301 vdc->get_vhost = vu_rng_get_vhost; 302 } 303 304 static const TypeInfo vu_rng_info = { 305 .name = TYPE_VHOST_USER_RNG, 306 .parent = TYPE_VIRTIO_DEVICE, 307 .instance_size = sizeof(VHostUserRNG), 308 .class_init = vu_rng_class_init, 309 }; 310 311 static void vu_rng_register_types(void) 312 { 313 type_register_static(&vu_rng_info); 314 } 315 316 type_init(vu_rng_register_types) 317