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 10867b15ccSJean-Philippe Brucker #include <linux/byteorder.h> 11117d6495STianjia Zhang #include <linux/kernel.h> 12117d6495STianjia Zhang #include <linux/virtio_vsock.h> 13117d6495STianjia Zhang #include <linux/vhost.h> 14117d6495STianjia Zhang 15117d6495STianjia Zhang #define VIRTIO_VSOCK_QUEUE_SIZE 128 16117d6495STianjia Zhang 17117d6495STianjia Zhang static LIST_HEAD(vdevs); 18117d6495STianjia Zhang static int compat_id = -1; 19117d6495STianjia Zhang 20117d6495STianjia Zhang enum { 21117d6495STianjia Zhang VSOCK_VQ_RX = 0, /* for host to guest data */ 22117d6495STianjia Zhang VSOCK_VQ_TX = 1, /* for guest to host data */ 23117d6495STianjia Zhang VSOCK_VQ_EVENT = 2, 24117d6495STianjia Zhang VSOCK_VQ_MAX = 3, 25117d6495STianjia Zhang }; 26117d6495STianjia Zhang 27117d6495STianjia Zhang struct vsock_dev { 28117d6495STianjia Zhang struct virt_queue vqs[VSOCK_VQ_MAX]; 29117d6495STianjia Zhang struct virtio_vsock_config config; 30867b15ccSJean-Philippe Brucker u64 guest_cid; 31117d6495STianjia Zhang u32 features; 32117d6495STianjia Zhang int vhost_fd; 33117d6495STianjia Zhang struct virtio_device vdev; 34117d6495STianjia Zhang struct list_head list; 35117d6495STianjia Zhang struct kvm *kvm; 36117d6495STianjia Zhang }; 37117d6495STianjia Zhang 38117d6495STianjia Zhang static u8 *get_config(struct kvm *kvm, void *dev) 39117d6495STianjia Zhang { 40117d6495STianjia Zhang struct vsock_dev *vdev = dev; 41117d6495STianjia Zhang 42117d6495STianjia Zhang return ((u8 *)(&vdev->config)); 43117d6495STianjia Zhang } 44117d6495STianjia Zhang 45e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev) 46e4730284SMartin Radev { 47e4730284SMartin Radev struct vsock_dev *vdev = dev; 48e4730284SMartin Radev 49e4730284SMartin Radev return sizeof(vdev->config); 50e4730284SMartin Radev } 51e4730284SMartin Radev 523c8f82b8SJean-Philippe Brucker static u64 get_host_features(struct kvm *kvm, void *dev) 53117d6495STianjia Zhang { 54cf8358d3SJean-Philippe Brucker int r; 55cf8358d3SJean-Philippe Brucker u64 features; 56cf8358d3SJean-Philippe Brucker struct vsock_dev *vdev = dev; 57cf8358d3SJean-Philippe Brucker 58cf8358d3SJean-Philippe Brucker r = ioctl(vdev->vhost_fd, VHOST_GET_FEATURES, &features); 59cf8358d3SJean-Philippe Brucker if (r != 0) 60cf8358d3SJean-Philippe Brucker die_perror("VHOST_GET_FEATURES failed"); 61cf8358d3SJean-Philippe Brucker 62cf8358d3SJean-Philippe Brucker return features & 63cf8358d3SJean-Philippe Brucker (1ULL << VIRTIO_RING_F_EVENT_IDX | 64cf8358d3SJean-Philippe Brucker 1ULL << VIRTIO_RING_F_INDIRECT_DESC); 65117d6495STianjia Zhang } 66117d6495STianjia Zhang 67117d6495STianjia Zhang static bool is_event_vq(u32 vq) 68117d6495STianjia Zhang { 69117d6495STianjia Zhang return vq == VSOCK_VQ_EVENT; 70117d6495STianjia Zhang } 71117d6495STianjia Zhang 72609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq) 73117d6495STianjia Zhang { 74117d6495STianjia Zhang struct vsock_dev *vdev = dev; 75117d6495STianjia Zhang struct virt_queue *queue; 76117d6495STianjia Zhang 77117d6495STianjia Zhang compat__remove_message(compat_id); 78117d6495STianjia Zhang 79117d6495STianjia Zhang queue = &vdev->vqs[vq]; 80609ee906SJean-Philippe Brucker virtio_init_device_vq(kvm, &vdev->vdev, queue, VIRTIO_VSOCK_QUEUE_SIZE); 81117d6495STianjia Zhang 82745221e5SJean-Philippe Brucker if (vdev->vhost_fd == -1 || is_event_vq(vq)) 83117d6495STianjia Zhang return 0; 84117d6495STianjia Zhang 85745221e5SJean-Philippe Brucker virtio_vhost_set_vring(kvm, vdev->vhost_fd, vq, queue); 86117d6495STianjia Zhang return 0; 87117d6495STianjia Zhang } 88117d6495STianjia Zhang 89117d6495STianjia Zhang static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) 90117d6495STianjia Zhang { 91117d6495STianjia Zhang struct vsock_dev *vdev = dev; 92117d6495STianjia Zhang 93676c0c8aSJean-Philippe Brucker if (vdev->vhost_fd == -1 || is_event_vq(vq)) 94117d6495STianjia Zhang return; 95117d6495STianjia Zhang 96676c0c8aSJean-Philippe Brucker virtio_vhost_set_vring_kick(kvm, vdev->vhost_fd, vq, efd); 97117d6495STianjia Zhang } 98117d6495STianjia Zhang 99117d6495STianjia Zhang static void notify_status(struct kvm *kvm, void *dev, u32 status) 100117d6495STianjia Zhang { 101117d6495STianjia Zhang struct vsock_dev *vdev = dev; 102117d6495STianjia Zhang int r, start; 103117d6495STianjia Zhang 104867b15ccSJean-Philippe Brucker if (status & VIRTIO__STATUS_CONFIG) 105867b15ccSJean-Philippe Brucker vdev->config.guest_cid = cpu_to_le64(vdev->guest_cid); 106867b15ccSJean-Philippe Brucker 107cf8358d3SJean-Philippe Brucker if (status & VIRTIO__STATUS_START) { 108a8e397bbSJean-Philippe Brucker start = 1; 109cf8358d3SJean-Philippe Brucker 110cf8358d3SJean-Philippe Brucker r = ioctl(vdev->vhost_fd, VHOST_SET_FEATURES, 111cf8358d3SJean-Philippe Brucker &vdev->vdev.features); 112cf8358d3SJean-Philippe Brucker if (r != 0) 113cf8358d3SJean-Philippe Brucker die_perror("VHOST_SET_FEATURES failed"); 114cf8358d3SJean-Philippe Brucker } else if (status & VIRTIO__STATUS_STOP) { 115a8e397bbSJean-Philippe Brucker start = 0; 116cf8358d3SJean-Philippe Brucker } else { 117117d6495STianjia Zhang return; 118cf8358d3SJean-Philippe Brucker } 119117d6495STianjia Zhang 120117d6495STianjia Zhang r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_RUNNING, &start); 121117d6495STianjia Zhang if (r != 0) 122117d6495STianjia Zhang die("VHOST_VSOCK_SET_RUNNING failed %d", errno); 123117d6495STianjia Zhang } 124117d6495STianjia Zhang 125117d6495STianjia Zhang static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 126117d6495STianjia Zhang { 127117d6495STianjia Zhang return 0; 128117d6495STianjia Zhang } 129117d6495STianjia Zhang 130117d6495STianjia Zhang static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq) 131117d6495STianjia Zhang { 132117d6495STianjia Zhang struct vsock_dev *vdev = dev; 133117d6495STianjia Zhang 134117d6495STianjia Zhang return &vdev->vqs[vq]; 135117d6495STianjia Zhang } 136117d6495STianjia Zhang 137117d6495STianjia Zhang static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 138117d6495STianjia Zhang { 139117d6495STianjia Zhang return VIRTIO_VSOCK_QUEUE_SIZE; 140117d6495STianjia Zhang } 141117d6495STianjia Zhang 142117d6495STianjia Zhang static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 143117d6495STianjia Zhang { 144117d6495STianjia Zhang return size; 145117d6495STianjia Zhang } 146117d6495STianjia Zhang 147117d6495STianjia Zhang static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) 148117d6495STianjia Zhang { 149117d6495STianjia Zhang struct vsock_dev *vdev = dev; 150117d6495STianjia Zhang 151029cd2bbSJean-Philippe Brucker if (vdev->vhost_fd == -1 || is_event_vq(vq)) 152117d6495STianjia Zhang return; 153117d6495STianjia Zhang 154*46aaf3b8SJean-Philippe Brucker virtio_vhost_set_vring_irqfd(kvm, gsi, &vdev->vqs[vq]); 155117d6495STianjia Zhang } 156117d6495STianjia Zhang 15731e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev) 158117d6495STianjia Zhang { 159117d6495STianjia Zhang return VSOCK_VQ_MAX; 160117d6495STianjia Zhang } 161117d6495STianjia Zhang 162117d6495STianjia Zhang static struct virtio_ops vsock_dev_virtio_ops = { 163117d6495STianjia Zhang .get_config = get_config, 164e4730284SMartin Radev .get_config_size = get_config_size, 165117d6495STianjia Zhang .get_host_features = get_host_features, 166117d6495STianjia Zhang .init_vq = init_vq, 167117d6495STianjia Zhang .get_vq = get_vq, 168117d6495STianjia Zhang .get_size_vq = get_size_vq, 169117d6495STianjia Zhang .set_size_vq = set_size_vq, 170117d6495STianjia Zhang .notify_vq_eventfd = notify_vq_eventfd, 171117d6495STianjia Zhang .notify_status = notify_status, 172117d6495STianjia Zhang .notify_vq_gsi = notify_vq_gsi, 173117d6495STianjia Zhang .notify_vq = notify_vq, 174117d6495STianjia Zhang .get_vq_count = get_vq_count, 175117d6495STianjia Zhang }; 176117d6495STianjia Zhang 177117d6495STianjia Zhang static void virtio_vhost_vsock_init(struct kvm *kvm, struct vsock_dev *vdev) 178117d6495STianjia Zhang { 179f84ab9ebSJean-Philippe Brucker int r; 180117d6495STianjia Zhang 181117d6495STianjia Zhang vdev->vhost_fd = open("/dev/vhost-vsock", O_RDWR); 182117d6495STianjia Zhang if (vdev->vhost_fd < 0) 183117d6495STianjia Zhang die_perror("Failed opening vhost-vsock device"); 184117d6495STianjia Zhang 185f84ab9ebSJean-Philippe Brucker virtio_vhost_init(kvm, vdev->vhost_fd); 186117d6495STianjia Zhang 187867b15ccSJean-Philippe Brucker r = ioctl(vdev->vhost_fd, VHOST_VSOCK_SET_GUEST_CID, &vdev->guest_cid); 188117d6495STianjia Zhang if (r != 0) 189117d6495STianjia Zhang die_perror("VHOST_VSOCK_SET_GUEST_CID failed"); 190117d6495STianjia Zhang 191117d6495STianjia Zhang vdev->vdev.use_vhost = true; 192117d6495STianjia Zhang } 193117d6495STianjia Zhang 194117d6495STianjia Zhang static int virtio_vsock_init_one(struct kvm *kvm, u64 guest_cid) 195117d6495STianjia Zhang { 196117d6495STianjia Zhang struct vsock_dev *vdev; 197117d6495STianjia Zhang int r; 198117d6495STianjia Zhang 199117d6495STianjia Zhang vdev = calloc(1, sizeof(struct vsock_dev)); 200117d6495STianjia Zhang if (vdev == NULL) 201117d6495STianjia Zhang return -ENOMEM; 202117d6495STianjia Zhang 203117d6495STianjia Zhang *vdev = (struct vsock_dev) { 204117d6495STianjia Zhang .guest_cid = guest_cid, 205117d6495STianjia Zhang .vhost_fd = -1, 206117d6495STianjia Zhang .kvm = kvm, 207117d6495STianjia Zhang }; 208117d6495STianjia Zhang 209117d6495STianjia Zhang list_add_tail(&vdev->list, &vdevs); 210117d6495STianjia Zhang 211117d6495STianjia Zhang r = virtio_init(kvm, vdev, &vdev->vdev, &vsock_dev_virtio_ops, 2129b46ebc5SRajnesh Kanwal kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_VSOCK, 213117d6495STianjia Zhang VIRTIO_ID_VSOCK, PCI_CLASS_VSOCK); 214117d6495STianjia Zhang if (r < 0) 215117d6495STianjia Zhang return r; 216117d6495STianjia Zhang 217117d6495STianjia Zhang virtio_vhost_vsock_init(kvm, vdev); 218117d6495STianjia Zhang 219117d6495STianjia Zhang if (compat_id == -1) 22033e026a7SJean-Philippe Brucker compat_id = virtio_compat_add_message("virtio-vsock", "CONFIG_VIRTIO_VSOCKETS"); 221117d6495STianjia Zhang 222117d6495STianjia Zhang return 0; 223117d6495STianjia Zhang } 224117d6495STianjia Zhang 225117d6495STianjia Zhang static int virtio_vsock_exit_one(struct kvm *kvm, struct vsock_dev *vdev) 226117d6495STianjia Zhang { 227117d6495STianjia Zhang list_del(&vdev->list); 228117d6495STianjia Zhang free(vdev); 229117d6495STianjia Zhang 230117d6495STianjia Zhang return 0; 231117d6495STianjia Zhang } 232117d6495STianjia Zhang 233117d6495STianjia Zhang int virtio_vsock_init(struct kvm *kvm) 234117d6495STianjia Zhang { 235117d6495STianjia Zhang int r; 236117d6495STianjia Zhang 237117d6495STianjia Zhang if (kvm->cfg.vsock_cid == 0) 238117d6495STianjia Zhang return 0; 239117d6495STianjia Zhang 240117d6495STianjia Zhang r = virtio_vsock_init_one(kvm, kvm->cfg.vsock_cid); 241117d6495STianjia Zhang if (r < 0) 242117d6495STianjia Zhang goto cleanup; 243117d6495STianjia Zhang 244117d6495STianjia Zhang return 0; 245117d6495STianjia Zhang cleanup: 246117d6495STianjia Zhang return virtio_vsock_exit(kvm); 247117d6495STianjia Zhang } 248117d6495STianjia Zhang virtio_dev_init(virtio_vsock_init); 249117d6495STianjia Zhang 250117d6495STianjia Zhang int virtio_vsock_exit(struct kvm *kvm) 251117d6495STianjia Zhang { 252117d6495STianjia Zhang while (!list_empty(&vdevs)) { 253117d6495STianjia Zhang struct vsock_dev *vdev; 254117d6495STianjia Zhang 255117d6495STianjia Zhang vdev = list_first_entry(&vdevs, struct vsock_dev, list); 256117d6495STianjia Zhang virtio_vsock_exit_one(kvm, vdev); 257117d6495STianjia Zhang } 258117d6495STianjia Zhang 259117d6495STianjia Zhang return 0; 260117d6495STianjia Zhang } 261117d6495STianjia Zhang virtio_dev_exit(virtio_vsock_exit); 262