1029cd2bbSJean-Philippe Brucker #include "kvm/irq.h"
2745221e5SJean-Philippe Brucker #include "kvm/virtio.h"
346aaf3b8SJean-Philippe Brucker #include "kvm/epoll.h"
4745221e5SJean-Philippe Brucker
5f84ab9ebSJean-Philippe Brucker #include <linux/kvm.h>
6f84ab9ebSJean-Philippe Brucker #include <linux/vhost.h>
7f84ab9ebSJean-Philippe Brucker #include <linux/list.h>
8f84ab9ebSJean-Philippe Brucker
9029cd2bbSJean-Philippe Brucker #include <sys/eventfd.h>
10029cd2bbSJean-Philippe Brucker
1146aaf3b8SJean-Philippe Brucker static struct kvm__epoll epoll;
1246aaf3b8SJean-Philippe Brucker
virtio_vhost_signal_vq(struct kvm * kvm,struct epoll_event * ev)1346aaf3b8SJean-Philippe Brucker static void virtio_vhost_signal_vq(struct kvm *kvm, struct epoll_event *ev)
1446aaf3b8SJean-Philippe Brucker {
1546aaf3b8SJean-Philippe Brucker int r;
1646aaf3b8SJean-Philippe Brucker u64 tmp;
1746aaf3b8SJean-Philippe Brucker struct virt_queue *queue = ev->data.ptr;
1846aaf3b8SJean-Philippe Brucker
1946aaf3b8SJean-Philippe Brucker if (read(queue->irqfd, &tmp, sizeof(tmp)) < 0)
2046aaf3b8SJean-Philippe Brucker pr_warning("%s: failed to read eventfd", __func__);
2146aaf3b8SJean-Philippe Brucker
2246aaf3b8SJean-Philippe Brucker r = queue->vdev->ops->signal_vq(kvm, queue->vdev, queue->index);
2346aaf3b8SJean-Philippe Brucker if (r)
2446aaf3b8SJean-Philippe Brucker pr_warning("%s failed to signal virtqueue", __func__);
2546aaf3b8SJean-Philippe Brucker }
2646aaf3b8SJean-Philippe Brucker
virtio_vhost_start_poll(struct kvm * kvm)2746aaf3b8SJean-Philippe Brucker static int virtio_vhost_start_poll(struct kvm *kvm)
2846aaf3b8SJean-Philippe Brucker {
2946aaf3b8SJean-Philippe Brucker if (epoll.fd)
3046aaf3b8SJean-Philippe Brucker return 0;
3146aaf3b8SJean-Philippe Brucker
3246aaf3b8SJean-Philippe Brucker if (epoll__init(kvm, &epoll, "vhost-irq-worker",
3346aaf3b8SJean-Philippe Brucker virtio_vhost_signal_vq))
3446aaf3b8SJean-Philippe Brucker return -1;
3546aaf3b8SJean-Philippe Brucker
3646aaf3b8SJean-Philippe Brucker return 0;
3746aaf3b8SJean-Philippe Brucker }
3846aaf3b8SJean-Philippe Brucker
virtio_vhost_stop_poll(struct kvm * kvm)3946aaf3b8SJean-Philippe Brucker static int virtio_vhost_stop_poll(struct kvm *kvm)
4046aaf3b8SJean-Philippe Brucker {
4146aaf3b8SJean-Philippe Brucker if (epoll.fd)
4246aaf3b8SJean-Philippe Brucker epoll__exit(&epoll);
4346aaf3b8SJean-Philippe Brucker return 0;
4446aaf3b8SJean-Philippe Brucker }
4546aaf3b8SJean-Philippe Brucker base_exit(virtio_vhost_stop_poll);
4646aaf3b8SJean-Philippe Brucker
virtio_vhost_init(struct kvm * kvm,int vhost_fd)47f84ab9ebSJean-Philippe Brucker void virtio_vhost_init(struct kvm *kvm, int vhost_fd)
48f84ab9ebSJean-Philippe Brucker {
49f84ab9ebSJean-Philippe Brucker struct kvm_mem_bank *bank;
50f84ab9ebSJean-Philippe Brucker struct vhost_memory *mem;
51f84ab9ebSJean-Philippe Brucker int i = 0, r;
52f84ab9ebSJean-Philippe Brucker
5346aaf3b8SJean-Philippe Brucker r = virtio_vhost_start_poll(kvm);
5446aaf3b8SJean-Philippe Brucker if (r)
5546aaf3b8SJean-Philippe Brucker die("Unable to start vhost polling thread\n");
5646aaf3b8SJean-Philippe Brucker
57f84ab9ebSJean-Philippe Brucker mem = calloc(1, sizeof(*mem) +
58f84ab9ebSJean-Philippe Brucker kvm->mem_slots * sizeof(struct vhost_memory_region));
59f84ab9ebSJean-Philippe Brucker if (mem == NULL)
60f84ab9ebSJean-Philippe Brucker die("Failed allocating memory for vhost memory map");
61f84ab9ebSJean-Philippe Brucker
62f84ab9ebSJean-Philippe Brucker list_for_each_entry(bank, &kvm->mem_banks, list) {
63f84ab9ebSJean-Philippe Brucker mem->regions[i] = (struct vhost_memory_region) {
64f84ab9ebSJean-Philippe Brucker .guest_phys_addr = bank->guest_phys_addr,
65f84ab9ebSJean-Philippe Brucker .memory_size = bank->size,
66f84ab9ebSJean-Philippe Brucker .userspace_addr = (unsigned long)bank->host_addr,
67f84ab9ebSJean-Philippe Brucker };
68f84ab9ebSJean-Philippe Brucker i++;
69f84ab9ebSJean-Philippe Brucker }
70f84ab9ebSJean-Philippe Brucker mem->nregions = i;
71f84ab9ebSJean-Philippe Brucker
72f84ab9ebSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_OWNER);
73f84ab9ebSJean-Philippe Brucker if (r != 0)
74f84ab9ebSJean-Philippe Brucker die_perror("VHOST_SET_OWNER failed");
75f84ab9ebSJean-Philippe Brucker
76f84ab9ebSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_MEM_TABLE, mem);
77f84ab9ebSJean-Philippe Brucker if (r != 0)
78f84ab9ebSJean-Philippe Brucker die_perror("VHOST_SET_MEM_TABLE failed");
79f84ab9ebSJean-Philippe Brucker
80f84ab9ebSJean-Philippe Brucker free(mem);
81f84ab9ebSJean-Philippe Brucker }
82745221e5SJean-Philippe Brucker
virtio_vhost_get_irqfd(struct virt_queue * queue)8346aaf3b8SJean-Philippe Brucker static int virtio_vhost_get_irqfd(struct virt_queue *queue)
8446aaf3b8SJean-Philippe Brucker {
8546aaf3b8SJean-Philippe Brucker if (!queue->irqfd) {
8646aaf3b8SJean-Philippe Brucker queue->irqfd = eventfd(0, 0);
8746aaf3b8SJean-Philippe Brucker if (queue->irqfd < 0)
8846aaf3b8SJean-Philippe Brucker die_perror("eventfd()");
8946aaf3b8SJean-Philippe Brucker }
9046aaf3b8SJean-Philippe Brucker return queue->irqfd;
9146aaf3b8SJean-Philippe Brucker }
9246aaf3b8SJean-Philippe Brucker
virtio_vhost_set_vring(struct kvm * kvm,int vhost_fd,u32 index,struct virt_queue * queue)93745221e5SJean-Philippe Brucker void virtio_vhost_set_vring(struct kvm *kvm, int vhost_fd, u32 index,
94745221e5SJean-Philippe Brucker struct virt_queue *queue)
95745221e5SJean-Philippe Brucker {
96745221e5SJean-Philippe Brucker int r;
97745221e5SJean-Philippe Brucker struct vhost_vring_addr addr = {
98745221e5SJean-Philippe Brucker .index = index,
99745221e5SJean-Philippe Brucker .desc_user_addr = (u64)(unsigned long)queue->vring.desc,
100745221e5SJean-Philippe Brucker .avail_user_addr = (u64)(unsigned long)queue->vring.avail,
101745221e5SJean-Philippe Brucker .used_user_addr = (u64)(unsigned long)queue->vring.used,
102745221e5SJean-Philippe Brucker };
103745221e5SJean-Philippe Brucker struct vhost_vring_state state = { .index = index };
10446aaf3b8SJean-Philippe Brucker struct vhost_vring_file file = {
10546aaf3b8SJean-Philippe Brucker .index = index,
10646aaf3b8SJean-Philippe Brucker .fd = virtio_vhost_get_irqfd(queue),
10746aaf3b8SJean-Philippe Brucker };
10846aaf3b8SJean-Philippe Brucker struct epoll_event event = {
10946aaf3b8SJean-Philippe Brucker .events = EPOLLIN,
11046aaf3b8SJean-Philippe Brucker .data.ptr = queue,
11146aaf3b8SJean-Philippe Brucker };
11246aaf3b8SJean-Philippe Brucker
11346aaf3b8SJean-Philippe Brucker queue->index = index;
114745221e5SJean-Philippe Brucker
115745221e5SJean-Philippe Brucker if (queue->endian != VIRTIO_ENDIAN_HOST)
116745221e5SJean-Philippe Brucker die("VHOST requires the same endianness in guest and host");
117745221e5SJean-Philippe Brucker
118745221e5SJean-Philippe Brucker state.num = queue->vring.num;
119745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_NUM, &state);
120745221e5SJean-Philippe Brucker if (r < 0)
121745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_NUM failed");
122745221e5SJean-Philippe Brucker
123745221e5SJean-Philippe Brucker state.num = 0;
124745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_BASE, &state);
125745221e5SJean-Philippe Brucker if (r < 0)
126745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_BASE failed");
127745221e5SJean-Philippe Brucker
128745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_ADDR, &addr);
129745221e5SJean-Philippe Brucker if (r < 0)
130745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_ADDR failed");
13146aaf3b8SJean-Philippe Brucker
13246aaf3b8SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file);
13346aaf3b8SJean-Philippe Brucker if (r < 0)
13446aaf3b8SJean-Philippe Brucker die_perror("VHOST_SET_VRING_CALL failed");
13546aaf3b8SJean-Philippe Brucker
13646aaf3b8SJean-Philippe Brucker r = epoll_ctl(epoll.fd, EPOLL_CTL_ADD, file.fd, &event);
13746aaf3b8SJean-Philippe Brucker if (r < 0)
13846aaf3b8SJean-Philippe Brucker die_perror("EPOLL_CTL_ADD vhost call fd");
139745221e5SJean-Philippe Brucker }
140676c0c8aSJean-Philippe Brucker
virtio_vhost_set_vring_kick(struct kvm * kvm,int vhost_fd,u32 index,int event_fd)141676c0c8aSJean-Philippe Brucker void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd,
142676c0c8aSJean-Philippe Brucker u32 index, int event_fd)
143676c0c8aSJean-Philippe Brucker {
144676c0c8aSJean-Philippe Brucker int r;
145676c0c8aSJean-Philippe Brucker struct vhost_vring_file file = {
146676c0c8aSJean-Philippe Brucker .index = index,
147676c0c8aSJean-Philippe Brucker .fd = event_fd,
148676c0c8aSJean-Philippe Brucker };
149676c0c8aSJean-Philippe Brucker
150676c0c8aSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_KICK, &file);
151676c0c8aSJean-Philippe Brucker if (r < 0)
152676c0c8aSJean-Philippe Brucker die_perror("VHOST_SET_VRING_KICK failed");
153676c0c8aSJean-Philippe Brucker }
154029cd2bbSJean-Philippe Brucker
virtio_vhost_set_vring_irqfd(struct kvm * kvm,u32 gsi,struct virt_queue * queue)15546aaf3b8SJean-Philippe Brucker void virtio_vhost_set_vring_irqfd(struct kvm *kvm, u32 gsi,
15646aaf3b8SJean-Philippe Brucker struct virt_queue *queue)
157029cd2bbSJean-Philippe Brucker {
158029cd2bbSJean-Philippe Brucker int r;
15946aaf3b8SJean-Philippe Brucker int fd = virtio_vhost_get_irqfd(queue);
160029cd2bbSJean-Philippe Brucker
16146aaf3b8SJean-Philippe Brucker if (queue->gsi)
16246aaf3b8SJean-Philippe Brucker irq__del_irqfd(kvm, queue->gsi, fd);
16346aaf3b8SJean-Philippe Brucker else
16446aaf3b8SJean-Philippe Brucker /* Disconnect user polling thread */
16546aaf3b8SJean-Philippe Brucker epoll_ctl(epoll.fd, EPOLL_CTL_DEL, fd, NULL);
16646aaf3b8SJean-Philippe Brucker
16746aaf3b8SJean-Philippe Brucker /* Connect the direct IRQFD route */
16846aaf3b8SJean-Philippe Brucker r = irq__add_irqfd(kvm, gsi, fd, -1);
169029cd2bbSJean-Philippe Brucker if (r < 0)
170029cd2bbSJean-Philippe Brucker die_perror("KVM_IRQFD failed");
171029cd2bbSJean-Philippe Brucker
172029cd2bbSJean-Philippe Brucker queue->gsi = gsi;
173029cd2bbSJean-Philippe Brucker }
174029cd2bbSJean-Philippe Brucker
virtio_vhost_reset_vring(struct kvm * kvm,int vhost_fd,u32 index,struct virt_queue * queue)175029cd2bbSJean-Philippe Brucker void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index,
176029cd2bbSJean-Philippe Brucker struct virt_queue *queue)
177029cd2bbSJean-Philippe Brucker
178029cd2bbSJean-Philippe Brucker {
17946aaf3b8SJean-Philippe Brucker struct vhost_vring_file file = {
18046aaf3b8SJean-Philippe Brucker .index = index,
18146aaf3b8SJean-Philippe Brucker .fd = -1,
18246aaf3b8SJean-Philippe Brucker };
18346aaf3b8SJean-Philippe Brucker
18446aaf3b8SJean-Philippe Brucker if (!queue->irqfd)
18546aaf3b8SJean-Philippe Brucker return;
18646aaf3b8SJean-Philippe Brucker
187029cd2bbSJean-Philippe Brucker if (queue->gsi) {
188029cd2bbSJean-Philippe Brucker irq__del_irqfd(kvm, queue->gsi, queue->irqfd);
18946aaf3b8SJean-Philippe Brucker queue->gsi = 0;
190029cd2bbSJean-Philippe Brucker }
19146aaf3b8SJean-Philippe Brucker
19246aaf3b8SJean-Philippe Brucker epoll_ctl(epoll.fd, EPOLL_CTL_DEL, queue->irqfd, NULL);
19346aaf3b8SJean-Philippe Brucker
19446aaf3b8SJean-Philippe Brucker if (ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file))
19546aaf3b8SJean-Philippe Brucker perror("SET_VRING_CALL");
19646aaf3b8SJean-Philippe Brucker close(queue->irqfd);
19746aaf3b8SJean-Philippe Brucker queue->irqfd = 0;
198029cd2bbSJean-Philippe Brucker }
199*3b1cdcf9SJean-Philippe Brucker
virtio_vhost_set_features(int vhost_fd,u64 features)200*3b1cdcf9SJean-Philippe Brucker int virtio_vhost_set_features(int vhost_fd, u64 features)
201*3b1cdcf9SJean-Philippe Brucker {
202*3b1cdcf9SJean-Philippe Brucker /*
203*3b1cdcf9SJean-Philippe Brucker * vhost interprets VIRTIO_F_ACCESS_PLATFORM as meaning there is an
204*3b1cdcf9SJean-Philippe Brucker * iotlb. Since this is not the case for kvmtool, mask it.
205*3b1cdcf9SJean-Philippe Brucker */
206*3b1cdcf9SJean-Philippe Brucker u64 masked_feat = features & ~(1ULL << VIRTIO_F_ACCESS_PLATFORM);
207*3b1cdcf9SJean-Philippe Brucker
208*3b1cdcf9SJean-Philippe Brucker return ioctl(vhost_fd, VHOST_SET_FEATURES, &masked_feat);
209*3b1cdcf9SJean-Philippe Brucker }
210