xref: /kvmtool/virtio/vhost.c (revision 676c0c8ad95bff2f1aa77f2899aa9ee13f66c7a1)
1745221e5SJean-Philippe Brucker #include "kvm/virtio.h"
2745221e5SJean-Philippe Brucker 
3f84ab9ebSJean-Philippe Brucker #include <linux/kvm.h>
4f84ab9ebSJean-Philippe Brucker #include <linux/vhost.h>
5f84ab9ebSJean-Philippe Brucker #include <linux/list.h>
6f84ab9ebSJean-Philippe Brucker 
7f84ab9ebSJean-Philippe Brucker void virtio_vhost_init(struct kvm *kvm, int vhost_fd)
8f84ab9ebSJean-Philippe Brucker {
9f84ab9ebSJean-Philippe Brucker 	struct kvm_mem_bank *bank;
10f84ab9ebSJean-Philippe Brucker 	struct vhost_memory *mem;
11f84ab9ebSJean-Philippe Brucker 	int i = 0, r;
12f84ab9ebSJean-Philippe Brucker 
13f84ab9ebSJean-Philippe Brucker 	mem = calloc(1, sizeof(*mem) +
14f84ab9ebSJean-Philippe Brucker 		     kvm->mem_slots * sizeof(struct vhost_memory_region));
15f84ab9ebSJean-Philippe Brucker 	if (mem == NULL)
16f84ab9ebSJean-Philippe Brucker 		die("Failed allocating memory for vhost memory map");
17f84ab9ebSJean-Philippe Brucker 
18f84ab9ebSJean-Philippe Brucker 	list_for_each_entry(bank, &kvm->mem_banks, list) {
19f84ab9ebSJean-Philippe Brucker 		mem->regions[i] = (struct vhost_memory_region) {
20f84ab9ebSJean-Philippe Brucker 			.guest_phys_addr = bank->guest_phys_addr,
21f84ab9ebSJean-Philippe Brucker 			.memory_size	 = bank->size,
22f84ab9ebSJean-Philippe Brucker 			.userspace_addr	 = (unsigned long)bank->host_addr,
23f84ab9ebSJean-Philippe Brucker 		};
24f84ab9ebSJean-Philippe Brucker 		i++;
25f84ab9ebSJean-Philippe Brucker 	}
26f84ab9ebSJean-Philippe Brucker 	mem->nregions = i;
27f84ab9ebSJean-Philippe Brucker 
28f84ab9ebSJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_OWNER);
29f84ab9ebSJean-Philippe Brucker 	if (r != 0)
30f84ab9ebSJean-Philippe Brucker 		die_perror("VHOST_SET_OWNER failed");
31f84ab9ebSJean-Philippe Brucker 
32f84ab9ebSJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_MEM_TABLE, mem);
33f84ab9ebSJean-Philippe Brucker 	if (r != 0)
34f84ab9ebSJean-Philippe Brucker 		die_perror("VHOST_SET_MEM_TABLE failed");
35f84ab9ebSJean-Philippe Brucker 
36f84ab9ebSJean-Philippe Brucker 	free(mem);
37f84ab9ebSJean-Philippe Brucker }
38745221e5SJean-Philippe Brucker 
39745221e5SJean-Philippe Brucker void virtio_vhost_set_vring(struct kvm *kvm, int vhost_fd, u32 index,
40745221e5SJean-Philippe Brucker 			    struct virt_queue *queue)
41745221e5SJean-Philippe Brucker {
42745221e5SJean-Philippe Brucker 	int r;
43745221e5SJean-Philippe Brucker 	struct vhost_vring_addr addr = {
44745221e5SJean-Philippe Brucker 		.index = index,
45745221e5SJean-Philippe Brucker 		.desc_user_addr = (u64)(unsigned long)queue->vring.desc,
46745221e5SJean-Philippe Brucker 		.avail_user_addr = (u64)(unsigned long)queue->vring.avail,
47745221e5SJean-Philippe Brucker 		.used_user_addr = (u64)(unsigned long)queue->vring.used,
48745221e5SJean-Philippe Brucker 	};
49745221e5SJean-Philippe Brucker 	struct vhost_vring_state state = { .index = index };
50745221e5SJean-Philippe Brucker 
51745221e5SJean-Philippe Brucker 	if (queue->endian != VIRTIO_ENDIAN_HOST)
52745221e5SJean-Philippe Brucker 		die("VHOST requires the same endianness in guest and host");
53745221e5SJean-Philippe Brucker 
54745221e5SJean-Philippe Brucker 	state.num = queue->vring.num;
55745221e5SJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_VRING_NUM, &state);
56745221e5SJean-Philippe Brucker 	if (r < 0)
57745221e5SJean-Philippe Brucker 		die_perror("VHOST_SET_VRING_NUM failed");
58745221e5SJean-Philippe Brucker 
59745221e5SJean-Philippe Brucker 	state.num = 0;
60745221e5SJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_VRING_BASE, &state);
61745221e5SJean-Philippe Brucker 	if (r < 0)
62745221e5SJean-Philippe Brucker 		die_perror("VHOST_SET_VRING_BASE failed");
63745221e5SJean-Philippe Brucker 
64745221e5SJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_VRING_ADDR, &addr);
65745221e5SJean-Philippe Brucker 	if (r < 0)
66745221e5SJean-Philippe Brucker 		die_perror("VHOST_SET_VRING_ADDR failed");
67745221e5SJean-Philippe Brucker }
68*676c0c8aSJean-Philippe Brucker 
69*676c0c8aSJean-Philippe Brucker void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd,
70*676c0c8aSJean-Philippe Brucker 				 u32 index, int event_fd)
71*676c0c8aSJean-Philippe Brucker {
72*676c0c8aSJean-Philippe Brucker 	int r;
73*676c0c8aSJean-Philippe Brucker 	struct vhost_vring_file file = {
74*676c0c8aSJean-Philippe Brucker 		.index	= index,
75*676c0c8aSJean-Philippe Brucker 		.fd	= event_fd,
76*676c0c8aSJean-Philippe Brucker 	};
77*676c0c8aSJean-Philippe Brucker 
78*676c0c8aSJean-Philippe Brucker 	r = ioctl(vhost_fd, VHOST_SET_VRING_KICK, &file);
79*676c0c8aSJean-Philippe Brucker 	if (r < 0)
80*676c0c8aSJean-Philippe Brucker 		die_perror("VHOST_SET_VRING_KICK failed");
81*676c0c8aSJean-Philippe Brucker }
82