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 virtio_delete_queue(rng->req_vq); 233 virtio_add_queue_failed: 234 virtio_cleanup(vdev); 235 vhost_user_cleanup(&rng->vhost_user); 236 } 237 238 static void vu_rng_device_unrealize(DeviceState *dev) 239 { 240 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 241 VHostUserRNG *rng = VHOST_USER_RNG(dev); 242 243 vu_rng_set_status(vdev, 0); 244 245 vhost_dev_cleanup(&rng->vhost_dev); 246 g_free(rng->vhost_dev.vqs); 247 rng->vhost_dev.vqs = NULL; 248 virtio_delete_queue(rng->req_vq); 249 virtio_cleanup(vdev); 250 vhost_user_cleanup(&rng->vhost_user); 251 } 252 253 static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev) 254 { 255 VHostUserRNG *rng = VHOST_USER_RNG(vdev); 256 return &rng->vhost_dev; 257 } 258 259 static const VMStateDescription vu_rng_vmstate = { 260 .name = "vhost-user-rng", 261 .unmigratable = 1, 262 }; 263 264 static Property vu_rng_properties[] = { 265 DEFINE_PROP_CHR("chardev", VHostUserRNG, chardev), 266 DEFINE_PROP_END_OF_LIST(), 267 }; 268 269 static void vu_rng_class_init(ObjectClass *klass, void *data) 270 { 271 DeviceClass *dc = DEVICE_CLASS(klass); 272 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 273 274 device_class_set_props(dc, vu_rng_properties); 275 dc->vmsd = &vu_rng_vmstate; 276 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 277 278 vdc->realize = vu_rng_device_realize; 279 vdc->unrealize = vu_rng_device_unrealize; 280 vdc->get_features = vu_rng_get_features; 281 vdc->set_status = vu_rng_set_status; 282 vdc->guest_notifier_mask = vu_rng_guest_notifier_mask; 283 vdc->guest_notifier_pending = vu_rng_guest_notifier_pending; 284 vdc->get_vhost = vu_rng_get_vhost; 285 } 286 287 static const TypeInfo vu_rng_info = { 288 .name = TYPE_VHOST_USER_RNG, 289 .parent = TYPE_VIRTIO_DEVICE, 290 .instance_size = sizeof(VHostUserRNG), 291 .class_init = vu_rng_class_init, 292 }; 293 294 static void vu_rng_register_types(void) 295 { 296 type_register_static(&vu_rng_info); 297 } 298 299 type_init(vu_rng_register_types) 300