1 /* 2 * vhost-backend 3 * 4 * Copyright (c) 2013 Virtual Open Systems Sarl. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 #include <linux/vhost.h> 13 #include <sys/ioctl.h> 14 #include "hw/virtio/vhost.h" 15 #include "hw/virtio/vhost-backend.h" 16 #include "qemu/error-report.h" 17 18 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, 19 void *arg) 20 { 21 int fd = (uintptr_t) dev->opaque; 22 23 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 24 25 return ioctl(fd, request, arg); 26 } 27 28 static int vhost_kernel_init(struct vhost_dev *dev, void *opaque) 29 { 30 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 31 32 dev->opaque = opaque; 33 34 return 0; 35 } 36 37 static int vhost_kernel_cleanup(struct vhost_dev *dev) 38 { 39 int fd = (uintptr_t) dev->opaque; 40 41 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 42 43 return close(fd); 44 } 45 46 static int vhost_kernel_memslots_limit(struct vhost_dev *dev) 47 { 48 int limit = 64; 49 char *s; 50 51 if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions", 52 &s, NULL, NULL)) { 53 uint64_t val = g_ascii_strtoull(s, NULL, 10); 54 if (!((val == G_MAXUINT64 || !val) && errno)) { 55 return val; 56 } 57 error_report("ignoring invalid max_mem_regions value in vhost module:" 58 " %s", s); 59 } 60 return limit; 61 } 62 63 static int vhost_kernel_net_set_backend(struct vhost_dev *dev, 64 struct vhost_vring_file *file) 65 { 66 return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file); 67 } 68 69 static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev, 70 struct vhost_scsi_target *target) 71 { 72 return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target); 73 } 74 75 static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev, 76 struct vhost_scsi_target *target) 77 { 78 return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target); 79 } 80 81 static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version) 82 { 83 return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version); 84 } 85 86 static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base, 87 struct vhost_log *log) 88 { 89 return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); 90 } 91 92 static int vhost_kernel_set_mem_table(struct vhost_dev *dev, 93 struct vhost_memory *mem) 94 { 95 return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem); 96 } 97 98 static int vhost_kernel_set_vring_addr(struct vhost_dev *dev, 99 struct vhost_vring_addr *addr) 100 { 101 return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr); 102 } 103 104 static int vhost_kernel_set_vring_endian(struct vhost_dev *dev, 105 struct vhost_vring_state *ring) 106 { 107 return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring); 108 } 109 110 static int vhost_kernel_set_vring_num(struct vhost_dev *dev, 111 struct vhost_vring_state *ring) 112 { 113 return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring); 114 } 115 116 static int vhost_kernel_set_vring_base(struct vhost_dev *dev, 117 struct vhost_vring_state *ring) 118 { 119 return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring); 120 } 121 122 static int vhost_kernel_get_vring_base(struct vhost_dev *dev, 123 struct vhost_vring_state *ring) 124 { 125 return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring); 126 } 127 128 static int vhost_kernel_set_vring_kick(struct vhost_dev *dev, 129 struct vhost_vring_file *file) 130 { 131 return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file); 132 } 133 134 static int vhost_kernel_set_vring_call(struct vhost_dev *dev, 135 struct vhost_vring_file *file) 136 { 137 return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file); 138 } 139 140 static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev, 141 struct vhost_vring_state *s) 142 { 143 return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s); 144 } 145 146 static int vhost_kernel_set_features(struct vhost_dev *dev, 147 uint64_t features) 148 { 149 return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features); 150 } 151 152 static int vhost_kernel_get_features(struct vhost_dev *dev, 153 uint64_t *features) 154 { 155 return vhost_kernel_call(dev, VHOST_GET_FEATURES, features); 156 } 157 158 static int vhost_kernel_set_owner(struct vhost_dev *dev) 159 { 160 return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL); 161 } 162 163 static int vhost_kernel_reset_device(struct vhost_dev *dev) 164 { 165 return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL); 166 } 167 168 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) 169 { 170 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); 171 172 return idx - dev->vq_index; 173 } 174 175 #ifdef CONFIG_VHOST_VSOCK 176 static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev, 177 uint64_t guest_cid) 178 { 179 return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid); 180 } 181 182 static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) 183 { 184 return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start); 185 } 186 #endif /* CONFIG_VHOST_VSOCK */ 187 188 static const VhostOps kernel_ops = { 189 .backend_type = VHOST_BACKEND_TYPE_KERNEL, 190 .vhost_backend_init = vhost_kernel_init, 191 .vhost_backend_cleanup = vhost_kernel_cleanup, 192 .vhost_backend_memslots_limit = vhost_kernel_memslots_limit, 193 .vhost_net_set_backend = vhost_kernel_net_set_backend, 194 .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint, 195 .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint, 196 .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version, 197 .vhost_set_log_base = vhost_kernel_set_log_base, 198 .vhost_set_mem_table = vhost_kernel_set_mem_table, 199 .vhost_set_vring_addr = vhost_kernel_set_vring_addr, 200 .vhost_set_vring_endian = vhost_kernel_set_vring_endian, 201 .vhost_set_vring_num = vhost_kernel_set_vring_num, 202 .vhost_set_vring_base = vhost_kernel_set_vring_base, 203 .vhost_get_vring_base = vhost_kernel_get_vring_base, 204 .vhost_set_vring_kick = vhost_kernel_set_vring_kick, 205 .vhost_set_vring_call = vhost_kernel_set_vring_call, 206 .vhost_set_vring_busyloop_timeout = 207 vhost_kernel_set_vring_busyloop_timeout, 208 .vhost_set_features = vhost_kernel_set_features, 209 .vhost_get_features = vhost_kernel_get_features, 210 .vhost_set_owner = vhost_kernel_set_owner, 211 .vhost_reset_device = vhost_kernel_reset_device, 212 .vhost_get_vq_index = vhost_kernel_get_vq_index, 213 #ifdef CONFIG_VHOST_VSOCK 214 .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, 215 .vhost_vsock_set_running = vhost_kernel_vsock_set_running, 216 #endif /* CONFIG_VHOST_VSOCK */ 217 }; 218 219 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) 220 { 221 int r = 0; 222 223 switch (backend_type) { 224 case VHOST_BACKEND_TYPE_KERNEL: 225 dev->vhost_ops = &kernel_ops; 226 break; 227 case VHOST_BACKEND_TYPE_USER: 228 dev->vhost_ops = &user_ops; 229 break; 230 default: 231 error_report("Unknown vhost backend type"); 232 r = -1; 233 } 234 235 return r; 236 } 237