162759896SAlex Bennée /* 262759896SAlex Bennée * Base vhost-user-base implementation. This can be used to derive a 362759896SAlex Bennée * more fully specified vhost-user backend either generically (see 462759896SAlex Bennée * vhost-user-device) or via a specific stub for a device which 562759896SAlex Bennée * encapsulates some fixed parameters. 662759896SAlex Bennée * 762759896SAlex Bennée * Copyright (c) 2023 Linaro Ltd 862759896SAlex Bennée * Author: Alex Bennée <alex.bennee@linaro.org> 962759896SAlex Bennée * 1062759896SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later 1162759896SAlex Bennée */ 1262759896SAlex Bennée 1362759896SAlex Bennée #include "qemu/osdep.h" 1462759896SAlex Bennée #include "qapi/error.h" 1562759896SAlex Bennée #include "hw/qdev-properties.h" 1662759896SAlex Bennée #include "hw/virtio/virtio-bus.h" 1762759896SAlex Bennée #include "hw/virtio/vhost-user-base.h" 1862759896SAlex Bennée #include "qemu/error-report.h" 1962759896SAlex Bennée 2062759896SAlex Bennée static void vub_start(VirtIODevice *vdev) 2162759896SAlex Bennée { 2262759896SAlex Bennée BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 2362759896SAlex Bennée VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 2462759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 2562759896SAlex Bennée int ret, i; 2662759896SAlex Bennée 2762759896SAlex Bennée if (!k->set_guest_notifiers) { 2862759896SAlex Bennée error_report("binding does not support guest notifiers"); 2962759896SAlex Bennée return; 3062759896SAlex Bennée } 3162759896SAlex Bennée 3262759896SAlex Bennée ret = vhost_dev_enable_notifiers(&vub->vhost_dev, vdev); 3362759896SAlex Bennée if (ret < 0) { 3462759896SAlex Bennée error_report("Error enabling host notifiers: %d", -ret); 3562759896SAlex Bennée return; 3662759896SAlex Bennée } 3762759896SAlex Bennée 3862759896SAlex Bennée ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, true); 3962759896SAlex Bennée if (ret < 0) { 4062759896SAlex Bennée error_report("Error binding guest notifier: %d", -ret); 4162759896SAlex Bennée goto err_host_notifiers; 4262759896SAlex Bennée } 4362759896SAlex Bennée 4462759896SAlex Bennée vub->vhost_dev.acked_features = vdev->guest_features; 4562759896SAlex Bennée 4662759896SAlex Bennée ret = vhost_dev_start(&vub->vhost_dev, vdev, true); 4762759896SAlex Bennée if (ret < 0) { 4862759896SAlex Bennée error_report("Error starting vhost-user-base: %d", -ret); 4962759896SAlex Bennée goto err_guest_notifiers; 5062759896SAlex Bennée } 5162759896SAlex Bennée 5262759896SAlex Bennée /* 5362759896SAlex Bennée * guest_notifier_mask/pending not used yet, so just unmask 5462759896SAlex Bennée * everything here. virtio-pci will do the right thing by 5562759896SAlex Bennée * enabling/disabling irqfd. 5662759896SAlex Bennée */ 5762759896SAlex Bennée for (i = 0; i < vub->vhost_dev.nvqs; i++) { 5862759896SAlex Bennée vhost_virtqueue_mask(&vub->vhost_dev, vdev, i, false); 5962759896SAlex Bennée } 6062759896SAlex Bennée 6162759896SAlex Bennée return; 6262759896SAlex Bennée 6362759896SAlex Bennée err_guest_notifiers: 6462759896SAlex Bennée k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 6562759896SAlex Bennée err_host_notifiers: 6662759896SAlex Bennée vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 6762759896SAlex Bennée } 6862759896SAlex Bennée 6962759896SAlex Bennée static void vub_stop(VirtIODevice *vdev) 7062759896SAlex Bennée { 7162759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 7262759896SAlex Bennée BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 7362759896SAlex Bennée VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 7462759896SAlex Bennée int ret; 7562759896SAlex Bennée 7662759896SAlex Bennée if (!k->set_guest_notifiers) { 7762759896SAlex Bennée return; 7862759896SAlex Bennée } 7962759896SAlex Bennée 8062759896SAlex Bennée vhost_dev_stop(&vub->vhost_dev, vdev, true); 8162759896SAlex Bennée 8262759896SAlex Bennée ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 8362759896SAlex Bennée if (ret < 0) { 8462759896SAlex Bennée error_report("vhost guest notifier cleanup failed: %d", ret); 8562759896SAlex Bennée return; 8662759896SAlex Bennée } 8762759896SAlex Bennée 8862759896SAlex Bennée vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 8962759896SAlex Bennée } 9062759896SAlex Bennée 9162759896SAlex Bennée static void vub_set_status(VirtIODevice *vdev, uint8_t status) 9262759896SAlex Bennée { 9362759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 9462759896SAlex Bennée bool should_start = virtio_device_should_start(vdev, status); 9562759896SAlex Bennée 9662759896SAlex Bennée if (vhost_dev_is_started(&vub->vhost_dev) == should_start) { 9762759896SAlex Bennée return; 9862759896SAlex Bennée } 9962759896SAlex Bennée 10062759896SAlex Bennée if (should_start) { 10162759896SAlex Bennée vub_start(vdev); 10262759896SAlex Bennée } else { 10362759896SAlex Bennée vub_stop(vdev); 10462759896SAlex Bennée } 10562759896SAlex Bennée } 10662759896SAlex Bennée 10762759896SAlex Bennée /* 10862759896SAlex Bennée * For an implementation where everything is delegated to the backend 10962759896SAlex Bennée * we don't do anything other than return the full feature set offered 11062759896SAlex Bennée * by the daemon (module the reserved feature bit). 11162759896SAlex Bennée */ 11262759896SAlex Bennée static uint64_t vub_get_features(VirtIODevice *vdev, 11362759896SAlex Bennée uint64_t requested_features, Error **errp) 11462759896SAlex Bennée { 11562759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 11662759896SAlex Bennée /* This should be set when the vhost connection initialises */ 11762759896SAlex Bennée g_assert(vub->vhost_dev.features); 11862759896SAlex Bennée return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES); 11962759896SAlex Bennée } 12062759896SAlex Bennée 12162759896SAlex Bennée /* 12262759896SAlex Bennée * To handle VirtIO config we need to know the size of the config 12362759896SAlex Bennée * space. We don't cache the config but re-fetch it from the guest 12462759896SAlex Bennée * every time in case something has changed. 12562759896SAlex Bennée */ 12662759896SAlex Bennée static void vub_get_config(VirtIODevice *vdev, uint8_t *config) 12762759896SAlex Bennée { 12862759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 12962759896SAlex Bennée Error *local_err = NULL; 13062759896SAlex Bennée 13162759896SAlex Bennée /* 13262759896SAlex Bennée * There will have been a warning during vhost_dev_init, but lets 13362759896SAlex Bennée * assert here as nothing will go right now. 13462759896SAlex Bennée */ 13562759896SAlex Bennée g_assert(vub->config_size && vub->vhost_user.supports_config == true); 13662759896SAlex Bennée 13762759896SAlex Bennée if (vhost_dev_get_config(&vub->vhost_dev, config, 13862759896SAlex Bennée vub->config_size, &local_err)) { 13962759896SAlex Bennée error_report_err(local_err); 14062759896SAlex Bennée } 14162759896SAlex Bennée } 14262759896SAlex Bennée 143a26105ddSLeo Yan static void vub_set_config(VirtIODevice *vdev, const uint8_t *config_data) 144a26105ddSLeo Yan { 145a26105ddSLeo Yan VHostUserBase *vub = VHOST_USER_BASE(vdev); 146a26105ddSLeo Yan int ret; 147a26105ddSLeo Yan 148a26105ddSLeo Yan g_assert(vub->config_size && vub->vhost_user.supports_config == true); 149a26105ddSLeo Yan 150a26105ddSLeo Yan ret = vhost_dev_set_config(&vub->vhost_dev, config_data, 151a26105ddSLeo Yan 0, vub->config_size, 152a26105ddSLeo Yan VHOST_SET_CONFIG_TYPE_FRONTEND); 153a26105ddSLeo Yan if (ret) { 154a26105ddSLeo Yan error_report("vhost guest set device config space failed: %d", ret); 155a26105ddSLeo Yan return; 156a26105ddSLeo Yan } 157a26105ddSLeo Yan } 158a26105ddSLeo Yan 15962759896SAlex Bennée /* 16062759896SAlex Bennée * When the daemon signals an update to the config we just need to 16162759896SAlex Bennée * signal the guest as we re-read the config on demand above. 16262759896SAlex Bennée */ 16362759896SAlex Bennée static int vub_config_notifier(struct vhost_dev *dev) 16462759896SAlex Bennée { 16562759896SAlex Bennée virtio_notify_config(dev->vdev); 16662759896SAlex Bennée return 0; 16762759896SAlex Bennée } 16862759896SAlex Bennée 16962759896SAlex Bennée const VhostDevConfigOps vub_config_ops = { 17062759896SAlex Bennée .vhost_dev_config_notifier = vub_config_notifier, 17162759896SAlex Bennée }; 17262759896SAlex Bennée 17362759896SAlex Bennée static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq) 17462759896SAlex Bennée { 17562759896SAlex Bennée /* 17662759896SAlex Bennée * Not normally called; it's the daemon that handles the queue; 17762759896SAlex Bennée * however virtio's cleanup path can call this. 17862759896SAlex Bennée */ 17962759896SAlex Bennée } 18062759896SAlex Bennée 18162759896SAlex Bennée static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub) 18262759896SAlex Bennée { 18362759896SAlex Bennée vhost_user_cleanup(&vub->vhost_user); 18462759896SAlex Bennée 18562759896SAlex Bennée for (int i = 0; i < vub->num_vqs; i++) { 18662759896SAlex Bennée VirtQueue *vq = g_ptr_array_index(vub->vqs, i); 18762759896SAlex Bennée virtio_delete_queue(vq); 18862759896SAlex Bennée } 18962759896SAlex Bennée 19062759896SAlex Bennée virtio_cleanup(vdev); 19162759896SAlex Bennée } 19262759896SAlex Bennée 19362759896SAlex Bennée static int vub_connect(DeviceState *dev) 19462759896SAlex Bennée { 19562759896SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 19662759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 19762759896SAlex Bennée struct vhost_dev *vhost_dev = &vub->vhost_dev; 19862759896SAlex Bennée 19962759896SAlex Bennée if (vub->connected) { 20062759896SAlex Bennée return 0; 20162759896SAlex Bennée } 20262759896SAlex Bennée vub->connected = true; 20362759896SAlex Bennée 20462759896SAlex Bennée /* 20562759896SAlex Bennée * If we support VHOST_USER_GET_CONFIG we must enable the notifier 20662759896SAlex Bennée * so we can ping the guest when it updates. 20762759896SAlex Bennée */ 20862759896SAlex Bennée if (vub->vhost_user.supports_config) { 20962759896SAlex Bennée vhost_dev_set_config_notifier(vhost_dev, &vub_config_ops); 21062759896SAlex Bennée } 21162759896SAlex Bennée 21262759896SAlex Bennée /* restore vhost state */ 21362759896SAlex Bennée if (virtio_device_started(vdev, vdev->status)) { 21462759896SAlex Bennée vub_start(vdev); 21562759896SAlex Bennée } 21662759896SAlex Bennée 21762759896SAlex Bennée return 0; 21862759896SAlex Bennée } 21962759896SAlex Bennée 22064a312a2SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event); 22164a312a2SAlex Bennée 22262759896SAlex Bennée static void vub_disconnect(DeviceState *dev) 22362759896SAlex Bennée { 22462759896SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 22562759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 22662759896SAlex Bennée 22762759896SAlex Bennée if (!vub->connected) { 22862759896SAlex Bennée return; 22962759896SAlex Bennée } 23062759896SAlex Bennée vub->connected = false; 23162759896SAlex Bennée 23262759896SAlex Bennée vub_stop(vdev); 23364a312a2SAlex Bennée vhost_dev_cleanup(&vub->vhost_dev); 23464a312a2SAlex Bennée 23564a312a2SAlex Bennée /* Re-instate the event handler for new connections */ 23664a312a2SAlex Bennée qemu_chr_fe_set_handlers(&vub->chardev, 23764a312a2SAlex Bennée NULL, NULL, vub_event, 23864a312a2SAlex Bennée NULL, dev, NULL, true); 23962759896SAlex Bennée } 24062759896SAlex Bennée 24162759896SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event) 24262759896SAlex Bennée { 24362759896SAlex Bennée DeviceState *dev = opaque; 24462759896SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 24562759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 24662759896SAlex Bennée 24762759896SAlex Bennée switch (event) { 24862759896SAlex Bennée case CHR_EVENT_OPENED: 24962759896SAlex Bennée if (vub_connect(dev) < 0) { 25062759896SAlex Bennée qemu_chr_fe_disconnect(&vub->chardev); 25162759896SAlex Bennée return; 25262759896SAlex Bennée } 25362759896SAlex Bennée break; 25462759896SAlex Bennée case CHR_EVENT_CLOSED: 25564a312a2SAlex Bennée /* defer close until later to avoid circular close */ 25664a312a2SAlex Bennée vhost_user_async_close(dev, &vub->chardev, &vub->vhost_dev, 257*9569fe0aSLi Feng vub_disconnect); 25862759896SAlex Bennée break; 25962759896SAlex Bennée case CHR_EVENT_BREAK: 26062759896SAlex Bennée case CHR_EVENT_MUX_IN: 26162759896SAlex Bennée case CHR_EVENT_MUX_OUT: 26262759896SAlex Bennée /* Ignore */ 26362759896SAlex Bennée break; 26462759896SAlex Bennée } 26562759896SAlex Bennée } 26662759896SAlex Bennée 26762759896SAlex Bennée static void vub_device_realize(DeviceState *dev, Error **errp) 26862759896SAlex Bennée { 26962759896SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 27062759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(dev); 27162759896SAlex Bennée int ret; 27262759896SAlex Bennée 27362759896SAlex Bennée if (!vub->chardev.chr) { 27462759896SAlex Bennée error_setg(errp, "vhost-user-base: missing chardev"); 27562759896SAlex Bennée return; 27662759896SAlex Bennée } 27762759896SAlex Bennée 27862759896SAlex Bennée if (!vub->virtio_id) { 27962759896SAlex Bennée error_setg(errp, "vhost-user-base: need to define device id"); 28062759896SAlex Bennée return; 28162759896SAlex Bennée } 28262759896SAlex Bennée 28362759896SAlex Bennée if (!vub->num_vqs) { 28462759896SAlex Bennée vub->num_vqs = 1; /* reasonable default? */ 28562759896SAlex Bennée } 28662759896SAlex Bennée 28762759896SAlex Bennée if (!vub->vq_size) { 28862759896SAlex Bennée vub->vq_size = 64; 28962759896SAlex Bennée } 29062759896SAlex Bennée 29162759896SAlex Bennée /* 29262759896SAlex Bennée * We can't handle config requests unless we know the size of the 29362759896SAlex Bennée * config region, specialisations of the vhost-user-base will be 29462759896SAlex Bennée * able to set this. 29562759896SAlex Bennée */ 29662759896SAlex Bennée if (vub->config_size) { 29762759896SAlex Bennée vub->vhost_user.supports_config = true; 29862759896SAlex Bennée } 29962759896SAlex Bennée 30062759896SAlex Bennée if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) { 30162759896SAlex Bennée return; 30262759896SAlex Bennée } 30362759896SAlex Bennée 30462759896SAlex Bennée virtio_init(vdev, vub->virtio_id, vub->config_size); 30562759896SAlex Bennée 30662759896SAlex Bennée /* 30762759896SAlex Bennée * Disable guest notifiers, by default all notifications will be via the 30862759896SAlex Bennée * asynchronous vhost-user socket. 30962759896SAlex Bennée */ 31062759896SAlex Bennée vdev->use_guest_notifier_mask = false; 31162759896SAlex Bennée 31262759896SAlex Bennée /* Allocate queues */ 31362759896SAlex Bennée vub->vqs = g_ptr_array_sized_new(vub->num_vqs); 31462759896SAlex Bennée for (int i = 0; i < vub->num_vqs; i++) { 31562759896SAlex Bennée g_ptr_array_add(vub->vqs, 31662759896SAlex Bennée virtio_add_queue(vdev, vub->vq_size, 31762759896SAlex Bennée vub_handle_output)); 31862759896SAlex Bennée } 31962759896SAlex Bennée 32062759896SAlex Bennée vub->vhost_dev.nvqs = vub->num_vqs; 32162759896SAlex Bennée vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs); 32262759896SAlex Bennée 32362759896SAlex Bennée /* connect to backend */ 32462759896SAlex Bennée ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user, 32562759896SAlex Bennée VHOST_BACKEND_TYPE_USER, 0, errp); 32662759896SAlex Bennée 32762759896SAlex Bennée if (ret < 0) { 32862759896SAlex Bennée do_vhost_user_cleanup(vdev, vub); 32962759896SAlex Bennée } 33062759896SAlex Bennée 33162759896SAlex Bennée qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL, 33262759896SAlex Bennée dev, NULL, true); 33362759896SAlex Bennée } 33462759896SAlex Bennée 33562759896SAlex Bennée static void vub_device_unrealize(DeviceState *dev) 33662759896SAlex Bennée { 33762759896SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 33862759896SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(dev); 33962759896SAlex Bennée struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs; 34062759896SAlex Bennée 34162759896SAlex Bennée /* This will stop vhost backend if appropriate. */ 34262759896SAlex Bennée vub_set_status(vdev, 0); 34362759896SAlex Bennée vhost_dev_cleanup(&vub->vhost_dev); 34462759896SAlex Bennée g_free(vhost_vqs); 34562759896SAlex Bennée do_vhost_user_cleanup(vdev, vub); 34662759896SAlex Bennée } 34762759896SAlex Bennée 34862759896SAlex Bennée static void vub_class_init(ObjectClass *klass, void *data) 34962759896SAlex Bennée { 35062759896SAlex Bennée VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 35162759896SAlex Bennée 35262759896SAlex Bennée vdc->realize = vub_device_realize; 35362759896SAlex Bennée vdc->unrealize = vub_device_unrealize; 35462759896SAlex Bennée vdc->get_features = vub_get_features; 35562759896SAlex Bennée vdc->get_config = vub_get_config; 356a26105ddSLeo Yan vdc->set_config = vub_set_config; 35762759896SAlex Bennée vdc->set_status = vub_set_status; 35862759896SAlex Bennée } 35962759896SAlex Bennée 36062759896SAlex Bennée static const TypeInfo vub_types[] = { 36162759896SAlex Bennée { 36262759896SAlex Bennée .name = TYPE_VHOST_USER_BASE, 36362759896SAlex Bennée .parent = TYPE_VIRTIO_DEVICE, 36462759896SAlex Bennée .instance_size = sizeof(VHostUserBase), 36562759896SAlex Bennée .class_init = vub_class_init, 36662759896SAlex Bennée .class_size = sizeof(VHostUserBaseClass), 36762759896SAlex Bennée .abstract = true 36862759896SAlex Bennée } 36962759896SAlex Bennée }; 37062759896SAlex Bennée 37162759896SAlex Bennée DEFINE_TYPES(vub_types) 372