master
h 167 lines 5.01 KB
Raw
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
27 union {
28 /*
29 * Total length of the available buffer that is writable by the device.
30 * Only used in packed vq.
31 */
32 uint32_t in_bytes;
33
34 /*
35 * Backup next field for each descriptor so we can recover securely, not
36 * needing to trust the device access. Only used in split vq.
37 */
38 uint16_t next;
39 };
40 } SVQDescState;
41
42 typedef struct VhostShadowVirtqueue VhostShadowVirtqueue;
43
44 /**
45 * Callback to handle an avail buffer.
46 *
47 * @svq: Shadow virtqueue
48 * @elem: Element placed in the queue by the guest
49 * @vq_callback_opaque: Opaque
50 *
51 * Returns 0 if the vq is running as expected.
52 *
53 * Note that ownership of elem is transferred to the callback.
54 */
55 typedef int (*VirtQueueAvailCallback)(VhostShadowVirtqueue *svq,
56 VirtQueueElement *elem,
57 void *vq_callback_opaque);
58
59 typedef struct VhostShadowVirtqueueOps {
60 VirtQueueAvailCallback avail_handler;
61 } VhostShadowVirtqueueOps;
62
63 /* Shadow virtqueue to relay notifications */
64 typedef struct VhostShadowVirtqueue {
65 /* Shadow vring */
66 struct vring vring;
67
68 /* Shadow kick notifier, sent to vhost */
69 EventNotifier hdev_kick;
70 /* Shadow call notifier, sent to vhost */
71 EventNotifier hdev_call;
72
73 /*
74 * Borrowed virtqueue's guest to host notifier. To borrow it in this event
75 * notifier allows to recover the VhostShadowVirtqueue from the event loop
76 * easily. If we use the VirtQueue's one, we don't have an easy way to
77 * retrieve VhostShadowVirtqueue.
78 *
79 * So shadow virtqueue must not clean it, or we would lose VirtQueue one.
80 */
81 EventNotifier svq_kick;
82
83 /* Guest's call notifier, where the SVQ calls guest. */
84 EventNotifier svq_call;
85
86 /* Virtio queue shadowing */
87 VirtQueue *vq;
88
89 /* Virtio device */
90 VirtIODevice *vdev;
91
92 /* IOVA mapping */
93 VhostIOVATree *iova_tree;
94
95 /* SVQ vring descriptors state */
96 SVQDescState *desc_state;
97
98 /* Next VirtQueue element that guest made available */
99 VirtQueueElement *next_guest_avail_elem;
100
101 /* Caller callbacks */
102 const VhostShadowVirtqueueOps *ops;
103
104 /* Caller callbacks opaque */
105 void *ops_opaque;
106
107 /* Next head to expose to the device */
108 uint16_t shadow_avail_idx;
109
110 /*
111 * Next free descriptor.
112 *
113 * Without IN_ORDER free_head is used as a linked list head, and
114 * desc_next[id] is the next element.
115 * With IN_ORDER free_head is the next available buffer index.
116 */
117 uint16_t free_head;
118
119 /*
120 * Last used element of the processing batch of used descriptors if
121 * IN_ORDER.
122 * If SVQ is not processing a batch of descriptors id is set to UINT_MAX.
123 */
124 vring_used_elem_t batch_last;
125
126 /* Last used id if IN_ORDER and split vq */
127 uint16_t last_used;
128
129 /* Last seen used idx */
130 uint16_t shadow_used_idx;
131
132 /* Next head to consume from the device */
133 uint16_t last_used_idx;
134
135 /* Size of SVQ vring free descriptors */
136 uint16_t num_free;
137 } VhostShadowVirtqueue;
138
139 bool vhost_svq_valid_features(uint64_t features, Error **errp);
140
141 uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq);
142 void vhost_svq_push_elem(VhostShadowVirtqueue *svq,
143 const VirtQueueElement *elem, uint32_t len);
144 int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
145 size_t out_num, const hwaddr *out_addr,
146 const struct iovec *in_sg, size_t in_num,
147 const hwaddr *in_addr, VirtQueueElement *elem);
148 size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num);
149
150 void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
151 void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
152 void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
153 struct vhost_vring_addr *addr);
154 size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
155 size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
156
157 void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
158 VirtQueue *vq, VhostIOVATree *iova_tree);
159 void vhost_svq_stop(VhostShadowVirtqueue *svq);
160
161 VhostShadowVirtqueue *vhost_svq_new(const VhostShadowVirtqueueOps *ops,
162 void *ops_opaque);
163
164 void vhost_svq_free(gpointer vq);
165 G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
166
167 #endif