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 "hw/virtio/vhost.h" 13 #include "hw/virtio/vhost-backend.h" 14 #include "qemu/error-report.h" 15 #include "qemu/main-loop.h" 16 #include "standard-headers/linux/vhost_types.h" 17 18 #ifdef CONFIG_VHOST_KERNEL 19 #include <linux/vhost.h> 20 #include <sys/ioctl.h> 21 22 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, 23 void *arg) 24 { 25 int fd = (uintptr_t) dev->opaque; 26 27 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 28 29 return ioctl(fd, request, arg); 30 } 31 32 static int vhost_kernel_init(struct vhost_dev *dev, void *opaque) 33 { 34 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 35 36 dev->opaque = opaque; 37 38 return 0; 39 } 40 41 static int vhost_kernel_cleanup(struct vhost_dev *dev) 42 { 43 int fd = (uintptr_t) dev->opaque; 44 45 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 46 47 return close(fd); 48 } 49 50 static int vhost_kernel_memslots_limit(struct vhost_dev *dev) 51 { 52 int limit = 64; 53 char *s; 54 55 if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions", 56 &s, NULL, NULL)) { 57 uint64_t val = g_ascii_strtoull(s, NULL, 10); 58 if (!((val == G_MAXUINT64 || !val) && errno)) { 59 g_free(s); 60 return val; 61 } 62 error_report("ignoring invalid max_mem_regions value in vhost module:" 63 " %s", s); 64 } 65 g_free(s); 66 return limit; 67 } 68 69 static int vhost_kernel_net_set_backend(struct vhost_dev *dev, 70 struct vhost_vring_file *file) 71 { 72 return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file); 73 } 74 75 static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev, 76 struct vhost_scsi_target *target) 77 { 78 return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target); 79 } 80 81 static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev, 82 struct vhost_scsi_target *target) 83 { 84 return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target); 85 } 86 87 static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version) 88 { 89 return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version); 90 } 91 92 static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base, 93 struct vhost_log *log) 94 { 95 return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); 96 } 97 98 static int vhost_kernel_set_mem_table(struct vhost_dev *dev, 99 struct vhost_memory *mem) 100 { 101 return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem); 102 } 103 104 static int vhost_kernel_set_vring_addr(struct vhost_dev *dev, 105 struct vhost_vring_addr *addr) 106 { 107 return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr); 108 } 109 110 static int vhost_kernel_set_vring_endian(struct vhost_dev *dev, 111 struct vhost_vring_state *ring) 112 { 113 return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring); 114 } 115 116 static int vhost_kernel_set_vring_num(struct vhost_dev *dev, 117 struct vhost_vring_state *ring) 118 { 119 return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring); 120 } 121 122 static int vhost_kernel_set_vring_base(struct vhost_dev *dev, 123 struct vhost_vring_state *ring) 124 { 125 return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring); 126 } 127 128 static int vhost_kernel_get_vring_base(struct vhost_dev *dev, 129 struct vhost_vring_state *ring) 130 { 131 return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring); 132 } 133 134 static int vhost_kernel_set_vring_kick(struct vhost_dev *dev, 135 struct vhost_vring_file *file) 136 { 137 return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file); 138 } 139 140 static int vhost_kernel_set_vring_call(struct vhost_dev *dev, 141 struct vhost_vring_file *file) 142 { 143 return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file); 144 } 145 146 static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev, 147 struct vhost_vring_state *s) 148 { 149 return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s); 150 } 151 152 static int vhost_kernel_set_features(struct vhost_dev *dev, 153 uint64_t features) 154 { 155 return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features); 156 } 157 158 static int vhost_kernel_get_features(struct vhost_dev *dev, 159 uint64_t *features) 160 { 161 return vhost_kernel_call(dev, VHOST_GET_FEATURES, features); 162 } 163 164 static int vhost_kernel_set_owner(struct vhost_dev *dev) 165 { 166 return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL); 167 } 168 169 static int vhost_kernel_reset_device(struct vhost_dev *dev) 170 { 171 return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL); 172 } 173 174 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) 175 { 176 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); 177 178 return idx - dev->vq_index; 179 } 180 181 #ifdef CONFIG_VHOST_VSOCK 182 static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev, 183 uint64_t guest_cid) 184 { 185 return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid); 186 } 187 188 static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) 189 { 190 return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start); 191 } 192 #endif /* CONFIG_VHOST_VSOCK */ 193 194 static void vhost_kernel_iotlb_read(void *opaque) 195 { 196 struct vhost_dev *dev = opaque; 197 struct vhost_msg msg; 198 ssize_t len; 199 200 while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) { 201 if (len < sizeof msg) { 202 error_report("Wrong vhost message len: %d", (int)len); 203 break; 204 } 205 if (msg.type != VHOST_IOTLB_MSG) { 206 error_report("Unknown vhost iotlb message type"); 207 break; 208 } 209 210 vhost_backend_handle_iotlb_msg(dev, &msg.iotlb); 211 } 212 } 213 214 static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev, 215 struct vhost_iotlb_msg *imsg) 216 { 217 struct vhost_msg msg; 218 219 msg.type = VHOST_IOTLB_MSG; 220 msg.iotlb = *imsg; 221 222 if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) { 223 error_report("Fail to update device iotlb"); 224 return -EFAULT; 225 } 226 227 return 0; 228 } 229 230 static void vhost_kernel_set_iotlb_callback(struct vhost_dev *dev, 231 int enabled) 232 { 233 if (enabled) 234 qemu_set_fd_handler((uintptr_t)dev->opaque, 235 vhost_kernel_iotlb_read, NULL, dev); 236 else 237 qemu_set_fd_handler((uintptr_t)dev->opaque, NULL, NULL, NULL); 238 } 239 240 static const VhostOps kernel_ops = { 241 .backend_type = VHOST_BACKEND_TYPE_KERNEL, 242 .vhost_backend_init = vhost_kernel_init, 243 .vhost_backend_cleanup = vhost_kernel_cleanup, 244 .vhost_backend_memslots_limit = vhost_kernel_memslots_limit, 245 .vhost_net_set_backend = vhost_kernel_net_set_backend, 246 .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint, 247 .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint, 248 .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version, 249 .vhost_set_log_base = vhost_kernel_set_log_base, 250 .vhost_set_mem_table = vhost_kernel_set_mem_table, 251 .vhost_set_vring_addr = vhost_kernel_set_vring_addr, 252 .vhost_set_vring_endian = vhost_kernel_set_vring_endian, 253 .vhost_set_vring_num = vhost_kernel_set_vring_num, 254 .vhost_set_vring_base = vhost_kernel_set_vring_base, 255 .vhost_get_vring_base = vhost_kernel_get_vring_base, 256 .vhost_set_vring_kick = vhost_kernel_set_vring_kick, 257 .vhost_set_vring_call = vhost_kernel_set_vring_call, 258 .vhost_set_vring_busyloop_timeout = 259 vhost_kernel_set_vring_busyloop_timeout, 260 .vhost_set_features = vhost_kernel_set_features, 261 .vhost_get_features = vhost_kernel_get_features, 262 .vhost_set_owner = vhost_kernel_set_owner, 263 .vhost_reset_device = vhost_kernel_reset_device, 264 .vhost_get_vq_index = vhost_kernel_get_vq_index, 265 #ifdef CONFIG_VHOST_VSOCK 266 .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid, 267 .vhost_vsock_set_running = vhost_kernel_vsock_set_running, 268 #endif /* CONFIG_VHOST_VSOCK */ 269 .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback, 270 .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg, 271 }; 272 #endif 273 274 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) 275 { 276 int r = 0; 277 278 switch (backend_type) { 279 #ifdef CONFIG_VHOST_KERNEL 280 case VHOST_BACKEND_TYPE_KERNEL: 281 dev->vhost_ops = &kernel_ops; 282 break; 283 #endif 284 #ifdef CONFIG_VHOST_USER 285 case VHOST_BACKEND_TYPE_USER: 286 dev->vhost_ops = &user_ops; 287 break; 288 #endif 289 default: 290 error_report("Unknown vhost backend type"); 291 r = -1; 292 } 293 294 return r; 295 } 296 297 int vhost_backend_update_device_iotlb(struct vhost_dev *dev, 298 uint64_t iova, uint64_t uaddr, 299 uint64_t len, 300 IOMMUAccessFlags perm) 301 { 302 struct vhost_iotlb_msg imsg; 303 304 imsg.iova = iova; 305 imsg.uaddr = uaddr; 306 imsg.size = len; 307 imsg.type = VHOST_IOTLB_UPDATE; 308 309 switch (perm) { 310 case IOMMU_RO: 311 imsg.perm = VHOST_ACCESS_RO; 312 break; 313 case IOMMU_WO: 314 imsg.perm = VHOST_ACCESS_WO; 315 break; 316 case IOMMU_RW: 317 imsg.perm = VHOST_ACCESS_RW; 318 break; 319 default: 320 return -EINVAL; 321 } 322 323 if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg) 324 return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); 325 326 return -ENODEV; 327 } 328 329 int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev, 330 uint64_t iova, uint64_t len) 331 { 332 struct vhost_iotlb_msg imsg; 333 334 imsg.iova = iova; 335 imsg.size = len; 336 imsg.type = VHOST_IOTLB_INVALIDATE; 337 338 if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg) 339 return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg); 340 341 return -ENODEV; 342 } 343 344 int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, 345 struct vhost_iotlb_msg *imsg) 346 { 347 int ret = 0; 348 349 switch (imsg->type) { 350 case VHOST_IOTLB_MISS: 351 ret = vhost_device_iotlb_miss(dev, imsg->iova, 352 imsg->perm != VHOST_ACCESS_RO); 353 break; 354 case VHOST_IOTLB_ACCESS_FAIL: 355 /* FIXME: report device iotlb error */ 356 error_report("Access failure IOTLB message type not supported"); 357 ret = -ENOTSUP; 358 break; 359 case VHOST_IOTLB_UPDATE: 360 case VHOST_IOTLB_INVALIDATE: 361 default: 362 error_report("Unexpected IOTLB message type"); 363 ret = -EINVAL; 364 break; 365 } 366 367 return ret; 368 } 369