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