1 // SPDX-License-Identifier: GPL-2.0
6 #include <sys/eventfd.h>
10 #include <sys/ioctl.h>
12 #include <sys/types.h>
15 #include <linux/virtio_types.h>
16 #include <linux/vhost.h>
17 #include <linux/virtio.h>
18 #include <linux/virtio_ring.h>
19 #include "../../drivers/vhost/test.h"
22 void *__kmalloc_fake
, *__kfree_ignore_start
, *__kfree_ignore_end
;
30 /* copy used for control */
36 struct virtio_device vdev
;
39 struct vq_info vqs
[1];
43 struct vhost_memory
*mem
;
46 bool vq_notify(struct virtqueue
*vq
)
48 struct vq_info
*info
= vq
->priv
;
49 unsigned long long v
= 1;
51 r
= write(info
->kick
, &v
, sizeof v
);
52 assert(r
== sizeof v
);
56 void vq_callback(struct virtqueue
*vq
)
61 void vhost_vq_setup(struct vdev_info
*dev
, struct vq_info
*info
)
63 struct vhost_vring_state state
= { .index
= info
->idx
};
64 struct vhost_vring_file file
= { .index
= info
->idx
};
65 unsigned long long features
= dev
->vdev
.features
;
66 struct vhost_vring_addr addr
= {
68 .desc_user_addr
= (uint64_t)(unsigned long)info
->vring
.desc
,
69 .avail_user_addr
= (uint64_t)(unsigned long)info
->vring
.avail
,
70 .used_user_addr
= (uint64_t)(unsigned long)info
->vring
.used
,
73 r
= ioctl(dev
->control
, VHOST_SET_FEATURES
, &features
);
75 state
.num
= info
->vring
.num
;
76 r
= ioctl(dev
->control
, VHOST_SET_VRING_NUM
, &state
);
79 r
= ioctl(dev
->control
, VHOST_SET_VRING_BASE
, &state
);
81 r
= ioctl(dev
->control
, VHOST_SET_VRING_ADDR
, &addr
);
84 r
= ioctl(dev
->control
, VHOST_SET_VRING_KICK
, &file
);
87 r
= ioctl(dev
->control
, VHOST_SET_VRING_CALL
, &file
);
91 static void vq_info_add(struct vdev_info
*dev
, int num
)
93 struct vq_info
*info
= &dev
->vqs
[dev
->nvqs
];
95 info
->idx
= dev
->nvqs
;
96 info
->kick
= eventfd(0, EFD_NONBLOCK
);
97 info
->call
= eventfd(0, EFD_NONBLOCK
);
98 r
= posix_memalign(&info
->ring
, 4096, vring_size(num
, 4096));
100 memset(info
->ring
, 0, vring_size(num
, 4096));
101 vring_init(&info
->vring
, num
, info
->ring
, 4096);
102 info
->vq
= vring_new_virtqueue(info
->idx
,
103 info
->vring
.num
, 4096, &dev
->vdev
,
104 true, false, info
->ring
,
105 vq_notify
, vq_callback
, "test");
107 info
->vq
->priv
= info
;
108 vhost_vq_setup(dev
, info
);
109 dev
->fds
[info
->idx
].fd
= info
->call
;
110 dev
->fds
[info
->idx
].events
= POLLIN
;
114 static void vdev_info_init(struct vdev_info
* dev
, unsigned long long features
)
117 memset(dev
, 0, sizeof *dev
);
118 dev
->vdev
.features
= features
;
119 dev
->buf_size
= 1024;
120 dev
->buf
= malloc(dev
->buf_size
);
122 dev
->control
= open("/dev/vhost-test", O_RDWR
);
123 assert(dev
->control
>= 0);
124 r
= ioctl(dev
->control
, VHOST_SET_OWNER
, NULL
);
126 dev
->mem
= malloc(offsetof(struct vhost_memory
, regions
) +
127 sizeof dev
->mem
->regions
[0]);
129 memset(dev
->mem
, 0, offsetof(struct vhost_memory
, regions
) +
130 sizeof dev
->mem
->regions
[0]);
131 dev
->mem
->nregions
= 1;
132 dev
->mem
->regions
[0].guest_phys_addr
= (long)dev
->buf
;
133 dev
->mem
->regions
[0].userspace_addr
= (long)dev
->buf
;
134 dev
->mem
->regions
[0].memory_size
= dev
->buf_size
;
135 r
= ioctl(dev
->control
, VHOST_SET_MEM_TABLE
, dev
->mem
);
139 /* TODO: this is pretty bad: we get a cache line bounce
140 * for the wait queue on poll and another one on read,
141 * plus the read which is there just to clear the
143 static void wait_for_interrupt(struct vdev_info
*dev
)
146 unsigned long long val
;
147 poll(dev
->fds
, dev
->nvqs
, -1);
148 for (i
= 0; i
< dev
->nvqs
; ++i
)
149 if (dev
->fds
[i
].revents
& POLLIN
) {
150 read(dev
->fds
[i
].fd
, &val
, sizeof val
);
154 static void run_test(struct vdev_info
*dev
, struct vq_info
*vq
,
155 bool delayed
, int bufs
)
157 struct scatterlist sl
;
158 long started
= 0, completed
= 0;
159 long completed_before
;
162 long long spurious
= 0;
163 r
= ioctl(dev
->control
, VHOST_TEST_RUN
, &test
);
166 virtqueue_disable_cb(vq
->vq
);
167 completed_before
= completed
;
169 if (started
< bufs
) {
170 sg_init_one(&sl
, dev
->buf
, dev
->buf_size
);
171 r
= virtqueue_add_outbuf(vq
->vq
, &sl
, 1,
174 if (likely(r
== 0)) {
176 if (unlikely(!virtqueue_kick(vq
->vq
)))
182 /* Flush out completed bufs if any */
183 if (virtqueue_get_buf(vq
->vq
, &len
)) {
189 if (completed
== completed_before
)
191 assert(completed
<= bufs
);
192 assert(started
<= bufs
);
193 if (completed
== bufs
)
196 if (virtqueue_enable_cb_delayed(vq
->vq
))
197 wait_for_interrupt(dev
);
199 if (virtqueue_enable_cb(vq
->vq
))
200 wait_for_interrupt(dev
);
204 r
= ioctl(dev
->control
, VHOST_TEST_RUN
, &test
);
206 fprintf(stderr
, "spurious wakeups: 0x%llx\n", spurious
);
209 const char optstring
[] = "h";
210 const struct option longopts
[] = {
220 .name
= "no-event-idx",
228 .name
= "no-indirect",
236 .name
= "no-virtio-1",
240 .name
= "delayed-interrupt",
244 .name
= "no-delayed-interrupt",
251 static void help(void)
253 fprintf(stderr
, "Usage: virtio_test [--help]"
257 " [--delayed-interrupt]"
261 int main(int argc
, char **argv
)
263 struct vdev_info dev
;
264 unsigned long long features
= (1ULL << VIRTIO_RING_F_INDIRECT_DESC
) |
265 (1ULL << VIRTIO_RING_F_EVENT_IDX
) | (1ULL << VIRTIO_F_VERSION_1
);
267 bool delayed
= false;
270 o
= getopt_long(argc
, argv
, optstring
, longopts
, NULL
);
278 features
&= ~(1ULL << VIRTIO_RING_F_EVENT_IDX
);
284 features
&= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC
);
287 features
&= ~(1ULL << VIRTIO_F_VERSION_1
);
299 vdev_info_init(&dev
, features
);
300 vq_info_add(&dev
, 256);
301 run_test(&dev
, &dev
.vqs
[0], delayed
, 0x100000);