1 /* 2 * Generic vhost-user stub. This can be used to connect to any 3 * vhost-user backend. All configuration details must be handled by 4 * the vhost-user daemon itself 5 * 6 * Copyright (c) 2023 Linaro Ltd 7 * Author: Alex Bennée <alex.bennee@linaro.org> 8 * 9 * SPDX-License-Identifier: GPL-2.0-or-later 10 */ 11 12 #include "qemu/osdep.h" 13 #include "qapi/error.h" 14 #include "hw/qdev-properties.h" 15 #include "hw/virtio/virtio-bus.h" 16 #include "hw/virtio/vhost-user-device.h" 17 #include "qemu/error-report.h" 18 19 static void vub_start(VirtIODevice *vdev) 20 { 21 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 22 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 23 VHostUserBase *vub = VHOST_USER_BASE(vdev); 24 int ret, i; 25 26 if (!k->set_guest_notifiers) { 27 error_report("binding does not support guest notifiers"); 28 return; 29 } 30 31 ret = vhost_dev_enable_notifiers(&vub->vhost_dev, vdev); 32 if (ret < 0) { 33 error_report("Error enabling host notifiers: %d", -ret); 34 return; 35 } 36 37 ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, true); 38 if (ret < 0) { 39 error_report("Error binding guest notifier: %d", -ret); 40 goto err_host_notifiers; 41 } 42 43 vub->vhost_dev.acked_features = vdev->guest_features; 44 45 ret = vhost_dev_start(&vub->vhost_dev, vdev, true); 46 if (ret < 0) { 47 error_report("Error starting vhost-user-device: %d", -ret); 48 goto err_guest_notifiers; 49 } 50 51 /* 52 * guest_notifier_mask/pending not used yet, so just unmask 53 * everything here. virtio-pci will do the right thing by 54 * enabling/disabling irqfd. 55 */ 56 for (i = 0; i < vub->vhost_dev.nvqs; i++) { 57 vhost_virtqueue_mask(&vub->vhost_dev, vdev, i, false); 58 } 59 60 return; 61 62 err_guest_notifiers: 63 k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 64 err_host_notifiers: 65 vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 66 } 67 68 static void vub_stop(VirtIODevice *vdev) 69 { 70 VHostUserBase *vub = VHOST_USER_BASE(vdev); 71 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 72 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 73 int ret; 74 75 if (!k->set_guest_notifiers) { 76 return; 77 } 78 79 vhost_dev_stop(&vub->vhost_dev, vdev, true); 80 81 ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 82 if (ret < 0) { 83 error_report("vhost guest notifier cleanup failed: %d", ret); 84 return; 85 } 86 87 vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 88 } 89 90 static void vub_set_status(VirtIODevice *vdev, uint8_t status) 91 { 92 VHostUserBase *vub = VHOST_USER_BASE(vdev); 93 bool should_start = virtio_device_should_start(vdev, status); 94 95 if (vhost_dev_is_started(&vub->vhost_dev) == should_start) { 96 return; 97 } 98 99 if (should_start) { 100 vub_start(vdev); 101 } else { 102 vub_stop(vdev); 103 } 104 } 105 106 /* 107 * For an implementation where everything is delegated to the backend 108 * we don't do anything other than return the full feature set offered 109 * by the daemon (module the reserved feature bit). 110 */ 111 static uint64_t vub_get_features(VirtIODevice *vdev, 112 uint64_t requested_features, Error **errp) 113 { 114 VHostUserBase *vub = VHOST_USER_BASE(vdev); 115 /* This should be set when the vhost connection initialises */ 116 g_assert(vub->vhost_dev.features); 117 return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES); 118 } 119 120 /* 121 * To handle VirtIO config we need to know the size of the config 122 * space. We don't cache the config but re-fetch it from the guest 123 * every time in case something has changed. 124 */ 125 static void vub_get_config(VirtIODevice *vdev, uint8_t *config) 126 { 127 VHostUserBase *vub = VHOST_USER_BASE(vdev); 128 Error *local_err = NULL; 129 130 /* 131 * There will have been a warning during vhost_dev_init, but lets 132 * assert here as nothing will go right now. 133 */ 134 g_assert(vub->config_size && vub->vhost_user.supports_config == true); 135 136 if (vhost_dev_get_config(&vub->vhost_dev, config, 137 vub->config_size, &local_err)) { 138 error_report_err(local_err); 139 } 140 } 141 142 /* 143 * When the daemon signals an update to the config we just need to 144 * signal the guest as we re-read the config on demand above. 145 */ 146 static int vub_config_notifier(struct vhost_dev *dev) 147 { 148 virtio_notify_config(dev->vdev); 149 return 0; 150 } 151 152 const VhostDevConfigOps vub_config_ops = { 153 .vhost_dev_config_notifier = vub_config_notifier, 154 }; 155 156 static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq) 157 { 158 /* 159 * Not normally called; it's the daemon that handles the queue; 160 * however virtio's cleanup path can call this. 161 */ 162 } 163 164 static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub) 165 { 166 vhost_user_cleanup(&vub->vhost_user); 167 168 for (int i = 0; i < vub->num_vqs; i++) { 169 VirtQueue *vq = g_ptr_array_index(vub->vqs, i); 170 virtio_delete_queue(vq); 171 } 172 173 virtio_cleanup(vdev); 174 } 175 176 static int vub_connect(DeviceState *dev) 177 { 178 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 179 VHostUserBase *vub = VHOST_USER_BASE(vdev); 180 struct vhost_dev *vhost_dev = &vub->vhost_dev; 181 182 if (vub->connected) { 183 return 0; 184 } 185 vub->connected = true; 186 187 /* 188 * If we support VHOST_USER_GET_CONFIG we must enable the notifier 189 * so we can ping the guest when it updates. 190 */ 191 if (vub->vhost_user.supports_config) { 192 vhost_dev_set_config_notifier(vhost_dev, &vub_config_ops); 193 } 194 195 /* restore vhost state */ 196 if (virtio_device_started(vdev, vdev->status)) { 197 vub_start(vdev); 198 } 199 200 return 0; 201 } 202 203 static void vub_disconnect(DeviceState *dev) 204 { 205 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 206 VHostUserBase *vub = VHOST_USER_BASE(vdev); 207 208 if (!vub->connected) { 209 return; 210 } 211 vub->connected = false; 212 213 if (vhost_dev_is_started(&vub->vhost_dev)) { 214 vub_stop(vdev); 215 } 216 } 217 218 static void vub_event(void *opaque, QEMUChrEvent event) 219 { 220 DeviceState *dev = opaque; 221 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 222 VHostUserBase *vub = VHOST_USER_BASE(vdev); 223 224 switch (event) { 225 case CHR_EVENT_OPENED: 226 if (vub_connect(dev) < 0) { 227 qemu_chr_fe_disconnect(&vub->chardev); 228 return; 229 } 230 break; 231 case CHR_EVENT_CLOSED: 232 vub_disconnect(dev); 233 break; 234 case CHR_EVENT_BREAK: 235 case CHR_EVENT_MUX_IN: 236 case CHR_EVENT_MUX_OUT: 237 /* Ignore */ 238 break; 239 } 240 } 241 242 static void vub_device_realize(DeviceState *dev, Error **errp) 243 { 244 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 245 VHostUserBase *vub = VHOST_USER_BASE(dev); 246 int ret; 247 248 if (!vub->chardev.chr) { 249 error_setg(errp, "vhost-user-device: missing chardev"); 250 return; 251 } 252 253 if (!vub->virtio_id) { 254 error_setg(errp, "vhost-user-device: need to define device id"); 255 return; 256 } 257 258 if (!vub->num_vqs) { 259 vub->num_vqs = 1; /* reasonable default? */ 260 } 261 262 /* 263 * We can't handle config requests unless we know the size of the 264 * config region, specialisations of the vhost-user-device will be 265 * able to set this. 266 */ 267 if (vub->config_size) { 268 vub->vhost_user.supports_config = true; 269 } 270 271 if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) { 272 return; 273 } 274 275 virtio_init(vdev, vub->virtio_id, vub->config_size); 276 277 /* 278 * Disable guest notifiers, by default all notifications will be via the 279 * asynchronous vhost-user socket. 280 */ 281 vdev->use_guest_notifier_mask = false; 282 283 /* Allocate queues */ 284 vub->vqs = g_ptr_array_sized_new(vub->num_vqs); 285 for (int i = 0; i < vub->num_vqs; i++) { 286 g_ptr_array_add(vub->vqs, 287 virtio_add_queue(vdev, 4, vub_handle_output)); 288 } 289 290 vub->vhost_dev.nvqs = vub->num_vqs; 291 vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs); 292 293 /* connect to backend */ 294 ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user, 295 VHOST_BACKEND_TYPE_USER, 0, errp); 296 297 if (ret < 0) { 298 do_vhost_user_cleanup(vdev, vub); 299 } 300 301 qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL, 302 dev, NULL, true); 303 } 304 305 static void vub_device_unrealize(DeviceState *dev) 306 { 307 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 308 VHostUserBase *vub = VHOST_USER_BASE(dev); 309 struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs; 310 311 /* This will stop vhost backend if appropriate. */ 312 vub_set_status(vdev, 0); 313 vhost_dev_cleanup(&vub->vhost_dev); 314 g_free(vhost_vqs); 315 do_vhost_user_cleanup(vdev, vub); 316 } 317 318 static void vub_class_init(ObjectClass *klass, void *data) 319 { 320 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 321 322 vdc->realize = vub_device_realize; 323 vdc->unrealize = vub_device_unrealize; 324 vdc->get_features = vub_get_features; 325 vdc->get_config = vub_get_config; 326 vdc->set_status = vub_set_status; 327 } 328 329 static const TypeInfo vub_info = { 330 .name = TYPE_VHOST_USER_BASE, 331 .parent = TYPE_VIRTIO_DEVICE, 332 .instance_size = sizeof(VHostUserBase), 333 .class_init = vub_class_init, 334 .class_size = sizeof(VHostUserBaseClass), 335 .abstract = true 336 }; 337 338 339 /* 340 * The following is a concrete implementation of the base class which 341 * allows the user to define the key parameters via the command line. 342 */ 343 344 static const VMStateDescription vud_vmstate = { 345 .name = "vhost-user-device", 346 .unmigratable = 1, 347 }; 348 349 static Property vud_properties[] = { 350 DEFINE_PROP_CHR("chardev", VHostUserBase, chardev), 351 DEFINE_PROP_UINT16("virtio-id", VHostUserBase, virtio_id, 0), 352 DEFINE_PROP_UINT32("num_vqs", VHostUserBase, num_vqs, 1), 353 DEFINE_PROP_UINT32("config_size", VHostUserBase, config_size, 0), 354 DEFINE_PROP_END_OF_LIST(), 355 }; 356 357 static void vud_class_init(ObjectClass *klass, void *data) 358 { 359 DeviceClass *dc = DEVICE_CLASS(klass); 360 361 device_class_set_props(dc, vud_properties); 362 dc->vmsd = &vud_vmstate; 363 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 364 } 365 366 static const TypeInfo vud_info = { 367 .name = TYPE_VHOST_USER_DEVICE, 368 .parent = TYPE_VHOST_USER_BASE, 369 .instance_size = sizeof(VHostUserBase), 370 .class_init = vud_class_init, 371 .class_size = sizeof(VHostUserBaseClass), 372 }; 373 374 static void vu_register_types(void) 375 { 376 type_register_static(&vub_info); 377 type_register_static(&vud_info); 378 } 379 380 type_init(vu_register_types) 381