1 /* 2 * vhost shadow virtqueue 3 * 4 * SPDX-FileCopyrightText: Red Hat, Inc. 2021 5 * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #ifndef VHOST_SHADOW_VIRTQUEUE_H 11 #define VHOST_SHADOW_VIRTQUEUE_H 12 13 #include "qemu/event_notifier.h" 14 #include "hw/virtio/virtio.h" 15 #include "standard-headers/linux/vhost_types.h" 16 #include "hw/virtio/vhost-iova-tree.h" 17 18 typedef struct SVQDescState { 19 VirtQueueElement *elem; 20 21 /* 22 * Number of descriptors exposed to the device. May or may not match 23 * guest's 24 */ 25 unsigned int ndescs; 26 } SVQDescState; 27 28 typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; 29 30 /** 31 * Callback to handle an avail buffer. 32 * 33 * @svq: Shadow virtqueue 34 * @elem: Element placed in the queue by the guest 35 * @vq_callback_opaque: Opaque 36 * 37 * Returns 0 if the vq is running as expected. 38 * 39 * Note that ownership of elem is transferred to the callback. 40 */ 41 typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq, 42 VirtQueueElement *elem, 43 void *vq_callback_opaque); 44 45 typedef struct VhostShadowVirtqueueOps { 46 VirtQueueAvailCallback avail_handler; 47 } VhostShadowVirtqueueOps; 48 49 /* Shadow virtqueue to relay notifications */ 50 typedef struct VhostShadowVirtqueue { 51 /* Shadow vring */ 52 struct vring vring; 53 54 /* Shadow kick notifier, sent to vhost */ 55 EventNotifier hdev_kick; 56 /* Shadow call notifier, sent to vhost */ 57 EventNotifier hdev_call; 58 59 /* 60 * Borrowed virtqueue's guest to host notifier. To borrow it in this event 61 * notifier allows to recover the VhostShadowVirtqueue from the event loop 62 * easily. If we use the VirtQueue's one, we don't have an easy way to 63 * retrieve VhostShadowVirtqueue. 64 * 65 * So shadow virtqueue must not clean it, or we would lose VirtQueue one. 66 */ 67 EventNotifier svq_kick; 68 69 /* Guest's call notifier, where the SVQ calls guest. */ 70 EventNotifier svq_call; 71 72 /* Virtio queue shadowing */ 73 VirtQueue *vq; 74 75 /* Virtio device */ 76 VirtIODevice *vdev; 77 78 /* IOVA mapping */ 79 VhostIOVATree *iova_tree; 80 81 /* SVQ vring descriptors state */ 82 SVQDescState *desc_state; 83 84 /* Next VirtQueue element that guest made available */ 85 VirtQueueElement *next_guest_avail_elem; 86 87 /* 88 * Backup next field for each descriptor so we can recover securely, not 89 * needing to trust the device access. 90 */ 91 uint16_t *desc_next; 92 93 /* Caller callbacks */ 94 const VhostShadowVirtqueueOps *ops; 95 96 /* Caller callbacks opaque */ 97 void *ops_opaque; 98 99 /* Next head to expose to the device */ 100 uint16_t shadow_avail_idx; 101 102 /* Next free descriptor */ 103 uint16_t free_head; 104 105 /* Last seen used idx */ 106 uint16_t shadow_used_idx; 107 108 /* Next head to consume from the device */ 109 uint16_t last_used_idx; 110 111 /* Size of SVQ vring free descriptors */ 112 uint16_t num_free; 113 } VhostShadowVirtqueue; 114 115 bool vhost_svq_valid_features(uint64_t features, Error **errp); 116 117 uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq); 118 void vhost_svq_push_elem(VhostShadowVirtqueue *svq, 119 const VirtQueueElement *elem, uint32_t len); 120 int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg, 121 size_t out_num, const struct iovec *in_sg, size_t in_num, 122 VirtQueueElement *elem); 123 size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num); 124 125 void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd); 126 void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd); 127 void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq, 128 struct vhost_vring_addr *addr); 129 size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq); 130 size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq); 131 132 void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, 133 VirtQueue *vq, VhostIOVATree *iova_tree); 134 void vhost_svq_stop(VhostShadowVirtqueue *svq); 135 136 VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops, 137 void *ops_opaque); 138 139 void vhost_svq_free(gpointer vq); 140 G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free); 141 142 #endif 143