1117d6495STianjia Zhang #include "kvm/virtio-vsock.h" 2117d6495STianjia Zhang #include "kvm/virtio-pci-dev.h" 3117d6495STianjia Zhang #include "kvm/kvm.h" 4117d6495STianjia Zhang #include "kvm/pci.h" 5117d6495STianjia Zhang #include "kvm/ioeventfd.h" 6117d6495STianjia Zhang #include "kvm/guest_compat.h" 7117d6495STianjia Zhang #include "kvm/virtio-pci.h" 8117d6495STianjia Zhang #include "kvm/virtio.h" 9117d6495STianjia Zhang 10117d6495STianjia Zhang #include <linux/kernel.h> 11117d6495STianjia Zhang #include <linux/virtio_vsock.h> 12117d6495STianjia Zhang #include <linux/vhost.h> 13117d6495STianjia Zhang 14117d6495STianjia Zhang #define VIRTIO_VSOCK_QUEUE_SIZE 128 15117d6495STianjia Zhang 16117d6495STianjia Zhang static LIST_HEAD(vdevs); 17117d6495STianjia Zhang static int compat_id = -1; 18117d6495STianjia Zhang 19117d6495STianjia Zhang enum { 20117d6495STianjia Zhang VSOCK_VQ_RX = 0, /* for host to guest data */ 21117d6495STianjia Zhang VSOCK_VQ_TX = 1, /* for guest to host data */ 22117d6495STianjia Zhang VSOCK_VQ_EVENT = 2, 23117d6495STianjia Zhang VSOCK_VQ_MAX = 3, 24117d6495STianjia Zhang }; 25117d6495STianjia Zhang 26117d6495STianjia Zhang struct vsock_dev { 27117d6495STianjia Zhang struct virt_queue vqs[VSOCK_VQ_MAX]; 28117d6495STianjia Zhang struct virtio_vsock_config config; 29117d6495STianjia Zhang u32 features; 30117d6495STianjia Zhang int vhost_fd; 31117d6495STianjia Zhang struct virtio_device vdev; 32117d6495STianjia Zhang struct list_head list; 33117d6495STianjia Zhang struct kvm *kvm; 34117d6495STianjia Zhang }; 35117d6495STianjia Zhang 36117d6495STianjia Zhang static u8 *get_config(struct kvm *kvm, void *dev) 37117d6495STianjia Zhang { 38117d6495STianjia Zhang struct vsock_dev *vdev = dev; 39117d6495STianjia Zhang 40117d6495STianjia Zhang return ((u8 *)(&vdev->config)); 41117d6495STianjia Zhang } 42117d6495STianjia Zhang 43e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev) 44e4730284SMartin Radev { 45e4730284SMartin Radev struct vsock_dev *vdev = dev; 46e4730284SMartin Radev 47e4730284SMartin Radev return sizeof(vdev->config); 48e4730284SMartin Radev } 49e4730284SMartin Radev 50117d6495STianjia Zhang static u32 get_host_features(struct kvm *kvm, void *dev) 51117d6495STianjia Zhang { 52117d6495STianjia Zhang return 1UL << VIRTIO_RING_F_EVENT_IDX 53117d6495STianjia Zhang | 1UL << VIRTIO_RING_F_INDIRECT_DESC; 54117d6495STianjia Zhang } 55117d6495STianjia Zhang 56117d6495STianjia Zhang static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 57117d6495STianjia Zhang { 58117d6495STianjia Zhang struct vsock_dev *vdev = dev; 59117d6495STianjia Zhang 60117d6495STianjia Zhang vdev->features = features; 61117d6495STianjia Zhang } 62117d6495STianjia Zhang 63117d6495STianjia Zhang static bool is_event_vq(u32 vq) 64117d6495STianjia Zhang { 65117d6495STianjia Zhang return vq == VSOCK_VQ_EVENT; 66117d6495STianjia Zhang } 67117d6495STianjia Zhang 68117d6495STianjia Zhang static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, 69117d6495STianjia Zhang u32 pfn) 70117d6495STianjia Zhang { 71117d6495STianjia Zhang struct vhost_vring_state state = { .index = vq }; 72117d6495STianjia Zhang struct vhost_vring_addr addr; 73117d6495STianjia Zhang struct vsock_dev *vdev = dev; 74117d6495STianjia Zhang struct virt_queue *queue; 75117d6495STianjia Zhang void *p; 76117d6495STianjia Zhang int r; 77117d6495STianjia Zhang 78117d6495STianjia Zhang compat__remove_message(compat_id); 79117d6495STianjia Zhang 80117d6495STianjia Zhang queue = &vdev->vqs[vq]; 81117d6495STianjia Zhang queue->pfn = pfn; 82117d6495STianjia Zhang p = virtio_get_vq(kvm, queue->pfn, page_size); 83117d6495STianjia Zhang 84117d6495STianjia Zhang vring_init(&queue->vring, VIRTIO_VSOCK_QUEUE_SIZE, p, align); 85117d6495STianjia Zhang virtio_init_device_vq(&vdev->vdev, queue); 86117d6495STianjia Zhang 87117d6495STianjia Zhang if (vdev->vhost_fd == -1) 88117d6495STianjia Zhang return 0; 89117d6495STianjia Zhang 90117d6495STianjia Zhang if (is_event_vq(vq)) 91117d6495STianjia Zhang return 0; 92117d6495STianjia Zhang 93117d6495STianjia Zhang state.num = queue->vring.num; 94117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_NUM, &state); 95117d6495STianjia Zhang if (r < 0) 96117d6495STianjia Zhang die_perror("VHOST_SET_VRING_NUM failed"); 97117d6495STianjia Zhang 98117d6495STianjia Zhang state.num = 0; 99117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_BASE, &state); 100117d6495STianjia Zhang if (r < 0) 101117d6495STianjia Zhang die_perror("VHOST_SET_VRING_BASE failed"); 102117d6495STianjia Zhang 103117d6495STianjia Zhang addr = (struct vhost_vring_addr) { 104117d6495STianjia Zhang .index = vq, 105117d6495STianjia Zhang .desc_user_addr = (u64)(unsigned long)queue->vring.desc, 106117d6495STianjia Zhang .avail_user_addr = (u64)(unsigned long)queue->vring.avail, 107117d6495STianjia Zhang .used_user_addr = (u64)(unsigned long)queue->vring.used, 108117d6495STianjia Zhang }; 109117d6495STianjia Zhang 110117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_ADDR, &addr); 111117d6495STianjia Zhang if (r < 0) 112117d6495STianjia Zhang die_perror("VHOST_SET_VRING_ADDR failed"); 113117d6495STianjia Zhang 114117d6495STianjia Zhang return 0; 115117d6495STianjia Zhang } 116117d6495STianjia Zhang 117117d6495STianjia Zhang static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) 118117d6495STianjia Zhang { 119117d6495STianjia Zhang struct vsock_dev *vdev = dev; 120117d6495STianjia Zhang struct vhost_vring_file file = { 121117d6495STianjia Zhang .index = vq, 122117d6495STianjia Zhang .fd = efd, 123117d6495STianjia Zhang }; 124117d6495STianjia Zhang int r; 125117d6495STianjia Zhang 126117d6495STianjia Zhang if (is_event_vq(vq)) 127117d6495STianjia Zhang return; 128117d6495STianjia Zhang 129117d6495STianjia Zhang if (vdev->vhost_fd == -1) 130117d6495STianjia Zhang return; 131117d6495STianjia Zhang 132117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_KICK, &file); 133117d6495STianjia Zhang if (r < 0) 134117d6495STianjia Zhang die_perror("VHOST_SET_VRING_KICK failed"); 135117d6495STianjia Zhang } 136117d6495STianjia Zhang 137117d6495STianjia Zhang static void notify_status(struct kvm *kvm, void *dev, u32 status) 138117d6495STianjia Zhang { 139117d6495STianjia Zhang struct vsock_dev *vdev = dev; 140117d6495STianjia Zhang int r, start; 141117d6495STianjia Zhang 142*a8e397bbSJean-Philippe Brucker if (status & VIRTIO__STATUS_START) 143*a8e397bbSJean-Philippe Brucker start = 1; 144*a8e397bbSJean-Philippe Brucker else if (status & VIRTIO__STATUS_STOP) 145*a8e397bbSJean-Philippe Brucker start = 0; 146*a8e397bbSJean-Philippe Brucker else 147117d6495STianjia Zhang return; 148117d6495STianjia Zhang 149117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_RUNNING, &start); 150117d6495STianjia Zhang if (r != 0) 151117d6495STianjia Zhang die("VHOST_VSOCK_SET_RUNNING failed %d", errno); 152117d6495STianjia Zhang } 153117d6495STianjia Zhang 154117d6495STianjia Zhang static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 155117d6495STianjia Zhang { 156117d6495STianjia Zhang return 0; 157117d6495STianjia Zhang } 158117d6495STianjia Zhang 159117d6495STianjia Zhang static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq) 160117d6495STianjia Zhang { 161117d6495STianjia Zhang struct vsock_dev *vdev = dev; 162117d6495STianjia Zhang 163117d6495STianjia Zhang return &vdev->vqs[vq]; 164117d6495STianjia Zhang } 165117d6495STianjia Zhang 166117d6495STianjia Zhang static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 167117d6495STianjia Zhang { 168117d6495STianjia Zhang return VIRTIO_VSOCK_QUEUE_SIZE; 169117d6495STianjia Zhang } 170117d6495STianjia Zhang 171117d6495STianjia Zhang static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 172117d6495STianjia Zhang { 173117d6495STianjia Zhang return size; 174117d6495STianjia Zhang } 175117d6495STianjia Zhang 176117d6495STianjia Zhang static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) 177117d6495STianjia Zhang { 178117d6495STianjia Zhang struct vhost_vring_file file; 179117d6495STianjia Zhang struct vsock_dev *vdev = dev; 180117d6495STianjia Zhang struct kvm_irqfd irq; 181117d6495STianjia Zhang int r; 182117d6495STianjia Zhang 183117d6495STianjia Zhang if (vdev->vhost_fd == -1) 184117d6495STianjia Zhang return; 185117d6495STianjia Zhang 186117d6495STianjia Zhang if (is_event_vq(vq)) 187117d6495STianjia Zhang return; 188117d6495STianjia Zhang 189117d6495STianjia Zhang irq = (struct kvm_irqfd) { 190117d6495STianjia Zhang .gsi = gsi, 191117d6495STianjia Zhang .fd = eventfd(0, 0), 192117d6495STianjia Zhang }; 193117d6495STianjia Zhang file = (struct vhost_vring_file) { 194117d6495STianjia Zhang .index = vq, 195117d6495STianjia Zhang .fd = irq.fd, 196117d6495STianjia Zhang }; 197117d6495STianjia Zhang 198117d6495STianjia Zhang r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq); 199117d6495STianjia Zhang if (r < 0) 200117d6495STianjia Zhang die_perror("KVM_IRQFD failed"); 201117d6495STianjia Zhang 202117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_CALL, &file); 203117d6495STianjia Zhang if (r < 0) 204117d6495STianjia Zhang die_perror("VHOST_SET_VRING_CALL failed"); 205117d6495STianjia Zhang } 206117d6495STianjia Zhang 20731e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev) 208117d6495STianjia Zhang { 209117d6495STianjia Zhang return VSOCK_VQ_MAX; 210117d6495STianjia Zhang } 211117d6495STianjia Zhang 212117d6495STianjia Zhang static struct virtio_ops vsock_dev_virtio_ops = { 213117d6495STianjia Zhang .get_config = get_config, 214e4730284SMartin Radev .get_config_size = get_config_size, 215117d6495STianjia Zhang .get_host_features = get_host_features, 216117d6495STianjia Zhang .set_guest_features = set_guest_features, 217117d6495STianjia Zhang .init_vq = init_vq, 218117d6495STianjia Zhang .get_vq = get_vq, 219117d6495STianjia Zhang .get_size_vq = get_size_vq, 220117d6495STianjia Zhang .set_size_vq = set_size_vq, 221117d6495STianjia Zhang .notify_vq_eventfd = notify_vq_eventfd, 222117d6495STianjia Zhang .notify_status = notify_status, 223117d6495STianjia Zhang .notify_vq_gsi = notify_vq_gsi, 224117d6495STianjia Zhang .notify_vq = notify_vq, 225117d6495STianjia Zhang .get_vq_count = get_vq_count, 226117d6495STianjia Zhang }; 227117d6495STianjia Zhang 228117d6495STianjia Zhang static void virtio_vhost_vsock_init(struct kvm *kvm, struct vsock_dev *vdev) 229117d6495STianjia Zhang { 230117d6495STianjia Zhang struct kvm_mem_bank *bank; 231117d6495STianjia Zhang struct vhost_memory *mem; 232117d6495STianjia Zhang u64 features; 233117d6495STianjia Zhang int r, i; 234117d6495STianjia Zhang 235117d6495STianjia Zhang vdev->vhost_fd = open("/dev/vhost-vsock", O_RDWR); 236117d6495STianjia Zhang if (vdev->vhost_fd < 0) 237117d6495STianjia Zhang die_perror("Failed opening vhost-vsock device"); 238117d6495STianjia Zhang 239117d6495STianjia Zhang mem = calloc(1, sizeof(*mem) + sizeof(struct vhost_memory_region)); 240117d6495STianjia Zhang if (mem == NULL) 241117d6495STianjia Zhang die("Failed allocating memory for vhost memory map"); 242117d6495STianjia Zhang 243117d6495STianjia Zhang i = 0; 244117d6495STianjia Zhang list_for_each_entry(bank, &kvm->mem_banks, list) { 245117d6495STianjia Zhang mem->regions[i] = (struct vhost_memory_region) { 246117d6495STianjia Zhang .guest_phys_addr = bank->guest_phys_addr, 247117d6495STianjia Zhang .memory_size = bank->size, 248117d6495STianjia Zhang .userspace_addr = (unsigned long)bank->host_addr, 249117d6495STianjia Zhang }; 250117d6495STianjia Zhang i++; 251117d6495STianjia Zhang } 252117d6495STianjia Zhang mem->nregions = i; 253117d6495STianjia Zhang 254117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_OWNER); 255117d6495STianjia Zhang if (r != 0) 256117d6495STianjia Zhang die_perror("VHOST_SET_OWNER failed"); 257117d6495STianjia Zhang 258117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_MEM_TABLE, mem); 259117d6495STianjia Zhang if (r != 0) 260117d6495STianjia Zhang die_perror("VHOST_SET_MEM_TABLE failed"); 261117d6495STianjia Zhang 262117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_GET_FEATURES, &features); 263117d6495STianjia Zhang if (r != 0) 264117d6495STianjia Zhang die_perror("VHOST_GET_FEATURES failed"); 265117d6495STianjia Zhang 266117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_SET_FEATURES, &features); 267117d6495STianjia Zhang if (r != 0) 268117d6495STianjia Zhang die_perror("VHOST_SET_FEATURES failed"); 269117d6495STianjia Zhang 270117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_GUEST_CID, &vdev->config.guest_cid); 271117d6495STianjia Zhang if (r != 0) 272117d6495STianjia Zhang die_perror("VHOST_VSOCK_SET_GUEST_CID failed"); 273117d6495STianjia Zhang 274117d6495STianjia Zhang vdev->vdev.use_vhost = true; 275117d6495STianjia Zhang 276117d6495STianjia Zhang free(mem); 277117d6495STianjia Zhang } 278117d6495STianjia Zhang 279117d6495STianjia Zhang static int virtio_vsock_init_one(struct kvm *kvm, u64 guest_cid) 280117d6495STianjia Zhang { 281117d6495STianjia Zhang struct vsock_dev *vdev; 282117d6495STianjia Zhang int r; 283117d6495STianjia Zhang 284117d6495STianjia Zhang vdev = calloc(1, sizeof(struct vsock_dev)); 285117d6495STianjia Zhang if (vdev == NULL) 286117d6495STianjia Zhang return -ENOMEM; 287117d6495STianjia Zhang 288117d6495STianjia Zhang *vdev = (struct vsock_dev) { 289117d6495STianjia Zhang .config = (struct virtio_vsock_config) { 290117d6495STianjia Zhang .guest_cid = guest_cid, 291117d6495STianjia Zhang }, 292117d6495STianjia Zhang .vhost_fd = -1, 293117d6495STianjia Zhang .kvm = kvm, 294117d6495STianjia Zhang }; 295117d6495STianjia Zhang 296117d6495STianjia Zhang list_add_tail(&vdev->list, &vdevs); 297117d6495STianjia Zhang 298117d6495STianjia Zhang r = virtio_init(kvm, vdev, &vdev->vdev, &vsock_dev_virtio_ops, 299117d6495STianjia Zhang VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_VSOCK, 300117d6495STianjia Zhang VIRTIO_ID_VSOCK, PCI_CLASS_VSOCK); 301117d6495STianjia Zhang if (r < 0) 302117d6495STianjia Zhang return r; 303117d6495STianjia Zhang 304117d6495STianjia Zhang virtio_vhost_vsock_init(kvm, vdev); 305117d6495STianjia Zhang 306117d6495STianjia Zhang if (compat_id == -1) 307117d6495STianjia Zhang compat_id = virtio_compat_add_message("virtio-vsock", "CONFIG_VIRTIO_VSOCK"); 308117d6495STianjia Zhang 309117d6495STianjia Zhang return 0; 310117d6495STianjia Zhang } 311117d6495STianjia Zhang 312117d6495STianjia Zhang static int virtio_vsock_exit_one(struct kvm *kvm, struct vsock_dev *vdev) 313117d6495STianjia Zhang { 314117d6495STianjia Zhang list_del(&vdev->list); 315117d6495STianjia Zhang free(vdev); 316117d6495STianjia Zhang 317117d6495STianjia Zhang return 0; 318117d6495STianjia Zhang } 319117d6495STianjia Zhang 320117d6495STianjia Zhang int virtio_vsock_init(struct kvm *kvm) 321117d6495STianjia Zhang { 322117d6495STianjia Zhang int r; 323117d6495STianjia Zhang 324117d6495STianjia Zhang if (kvm->cfg.vsock_cid == 0) 325117d6495STianjia Zhang return 0; 326117d6495STianjia Zhang 327117d6495STianjia Zhang r = virtio_vsock_init_one(kvm, kvm->cfg.vsock_cid); 328117d6495STianjia Zhang if (r < 0) 329117d6495STianjia Zhang goto cleanup; 330117d6495STianjia Zhang 331117d6495STianjia Zhang return 0; 332117d6495STianjia Zhang cleanup: 333117d6495STianjia Zhang return virtio_vsock_exit(kvm); 334117d6495STianjia Zhang } 335117d6495STianjia Zhang virtio_dev_init(virtio_vsock_init); 336117d6495STianjia Zhang 337117d6495STianjia Zhang int virtio_vsock_exit(struct kvm *kvm) 338117d6495STianjia Zhang { 339117d6495STianjia Zhang while (!list_empty(&vdevs)) { 340117d6495STianjia Zhang struct vsock_dev *vdev; 341117d6495STianjia Zhang 342117d6495STianjia Zhang vdev = list_first_entry(&vdevs, struct vsock_dev, list); 343117d6495STianjia Zhang virtio_vsock_exit_one(kvm, vdev); 344117d6495STianjia Zhang } 345117d6495STianjia Zhang 346117d6495STianjia Zhang return 0; 347117d6495STianjia Zhang } 348117d6495STianjia Zhang virtio_dev_exit(virtio_vsock_exit); 349