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 /* Shadow virtqueue to relay notifications */
19 typedef struct VhostShadowVirtqueue {
20     /* Shadow vring */
21     struct vring vring;
22 
23     /* Shadow kick notifier, sent to vhost */
24     EventNotifier hdev_kick;
25     /* Shadow call notifier, sent to vhost */
26     EventNotifier hdev_call;
27 
28     /*
29      * Borrowed virtqueue's guest to host notifier. To borrow it in this event
30      * notifier allows to recover the VhostShadowVirtqueue from the event loop
31      * easily. If we use the VirtQueue's one, we don't have an easy way to
32      * retrieve VhostShadowVirtqueue.
33      *
34      * So shadow virtqueue must not clean it, or we would lose VirtQueue one.
35      */
36     EventNotifier svq_kick;
37 
38     /* Guest's call notifier, where the SVQ calls guest. */
39     EventNotifier svq_call;
40 
41     /* Virtio queue shadowing */
42     VirtQueue *vq;
43 
44     /* Virtio device */
45     VirtIODevice *vdev;
46 
47     /* IOVA mapping */
48     VhostIOVATree *iova_tree;
49 
50     /* Map for use the guest's descriptors */
51     VirtQueueElement **ring_id_maps;
52 
53     /* Next VirtQueue element that guest made available */
54     VirtQueueElement *next_guest_avail_elem;
55 
56     /*
57      * Backup next field for each descriptor so we can recover securely, not
58      * needing to trust the device access.
59      */
60     uint16_t *desc_next;
61 
62     /* Next head to expose to the device */
63     uint16_t shadow_avail_idx;
64 
65     /* Next free descriptor */
66     uint16_t free_head;
67 
68     /* Last seen used idx */
69     uint16_t shadow_used_idx;
70 
71     /* Next head to consume from the device */
72     uint16_t last_used_idx;
73 } VhostShadowVirtqueue;
74 
75 bool vhost_svq_valid_features(uint64_t features, Error **errp);
76 
77 void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
78 void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
79 void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
80                               struct vhost_vring_addr *addr);
81 size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
82 size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
83 
84 void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
85                      VirtQueue *vq);
86 void vhost_svq_stop(VhostShadowVirtqueue *svq);
87 
88 VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree);
89 
90 void vhost_svq_free(gpointer vq);
91 G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
92 
93 #endif
94