1416b2c2dSAsias He #include "kvm/virtio-console.h" 231638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h" 39bd8ac5cSAsias He #include "kvm/disk-image.h" 439d6af07SAsias He #include "kvm/virtio.h" 59bd8ac5cSAsias He #include "kvm/ioport.h" 69bd8ac5cSAsias He #include "kvm/util.h" 79bd8ac5cSAsias He #include "kvm/term.h" 87512639bSAsias He #include "kvm/mutex.h" 99bd8ac5cSAsias He #include "kvm/kvm.h" 109bd8ac5cSAsias He #include "kvm/pci.h" 11b6638c22SSasha Levin #include "kvm/threadpool.h" 122449f6e3SSasha Levin #include "kvm/irq.h" 13e59b1ed0SSasha Levin #include "kvm/guest_compat.h" 149bd8ac5cSAsias He 159bd8ac5cSAsias He #include <linux/virtio_console.h> 169bd8ac5cSAsias He #include <linux/virtio_ring.h> 179bd8ac5cSAsias He #include <linux/virtio_blk.h> 189bd8ac5cSAsias He 199bd8ac5cSAsias He #include <sys/uio.h> 209bd8ac5cSAsias He #include <sys/types.h> 219bd8ac5cSAsias He #include <sys/stat.h> 229bd8ac5cSAsias He #include <termios.h> 239bd8ac5cSAsias He #include <unistd.h> 249bd8ac5cSAsias He #include <fcntl.h> 259bd8ac5cSAsias He 269bd8ac5cSAsias He #define VIRTIO_CONSOLE_QUEUE_SIZE 128 279bd8ac5cSAsias He #define VIRTIO_CONSOLE_NUM_QUEUES 2 289bd8ac5cSAsias He #define VIRTIO_CONSOLE_RX_QUEUE 0 299bd8ac5cSAsias He #define VIRTIO_CONSOLE_TX_QUEUE 1 309bd8ac5cSAsias He 31a643306eSSasha Levin struct con_dev { 32d3476f7dSSasha Levin struct mutex mutex; 337512639bSAsias He 3402eca50cSAsias He struct virtio_device vdev; 359bd8ac5cSAsias He struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES]; 36c85b4b4dSSasha Levin struct virtio_console_config config; 37c85b4b4dSSasha Levin u32 features; 38b6638c22SSasha Levin 39*97bb5a9dSJonathan Austin pthread_cond_t poll_cond; 40*97bb5a9dSJonathan Austin int vq_ready; 41*97bb5a9dSJonathan Austin 42df0c7f57SSasha Levin struct thread_pool__job jobs[VIRTIO_CONSOLE_NUM_QUEUES]; 439bd8ac5cSAsias He }; 449bd8ac5cSAsias He 45a643306eSSasha Levin static struct con_dev cdev = { 46d3476f7dSSasha Levin .mutex = MUTEX_INITIALIZER, 477512639bSAsias He 48*97bb5a9dSJonathan Austin .vq_ready = 0, 49*97bb5a9dSJonathan Austin 50c85b4b4dSSasha Levin .config = { 519bd8ac5cSAsias He .cols = 80, 529bd8ac5cSAsias He .rows = 24, 539bd8ac5cSAsias He .max_nr_ports = 1, 549bd8ac5cSAsias He }, 559bd8ac5cSAsias He }; 569bd8ac5cSAsias He 57312c62d1SSasha Levin static int compat_id = -1; 58312c62d1SSasha Levin 599bd8ac5cSAsias He /* 609bd8ac5cSAsias He * Interrupts are injected for hvc0 only. 619bd8ac5cSAsias He */ 6243835ac9SSasha Levin static void virtio_console__inject_interrupt_callback(struct kvm *kvm, void *param) 639bd8ac5cSAsias He { 649bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 659bd8ac5cSAsias He struct virt_queue *vq; 663fdf659dSSasha Levin u16 out, in; 673fdf659dSSasha Levin u16 head; 689bd8ac5cSAsias He int len; 699bd8ac5cSAsias He 702651ea58SSasha Levin if (kvm->cfg.active_console != CONSOLE_VIRTIO) 712651ea58SSasha Levin return; 722651ea58SSasha Levin 73a643306eSSasha Levin mutex_lock(&cdev.mutex); 747512639bSAsias He 75b6638c22SSasha Levin vq = param; 769bd8ac5cSAsias He 77*97bb5a9dSJonathan Austin if (!cdev.vq_ready) 78*97bb5a9dSJonathan Austin pthread_cond_wait(&cdev.poll_cond, &cdev.mutex.mutex); 79*97bb5a9dSJonathan Austin 802651ea58SSasha Levin if (term_readable(0) && virt_queue__available(vq)) { 8143835ac9SSasha Levin head = virt_queue__get_iov(vq, iov, &out, &in, kvm); 824346fd8fSSasha Levin len = term_getc_iov(kvm, iov, in, 0); 839bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 8402eca50cSAsias He cdev.vdev.ops->signal_vq(kvm, &cdev.vdev, vq - cdev.vqs); 859bd8ac5cSAsias He } 867512639bSAsias He 87a643306eSSasha Levin mutex_unlock(&cdev.mutex); 889bd8ac5cSAsias He } 899bd8ac5cSAsias He 9043835ac9SSasha Levin void virtio_console__inject_interrupt(struct kvm *kvm) 91b6638c22SSasha Levin { 92*97bb5a9dSJonathan Austin virtio_console__inject_interrupt_callback(kvm, 93*97bb5a9dSJonathan Austin &cdev.vqs[VIRTIO_CONSOLE_RX_QUEUE]); 94b6638c22SSasha Levin } 95b6638c22SSasha Levin 9643835ac9SSasha Levin static void virtio_console_handle_callback(struct kvm *kvm, void *param) 979bd8ac5cSAsias He { 989bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 999bd8ac5cSAsias He struct virt_queue *vq; 1003fdf659dSSasha Levin u16 out, in; 1013fdf659dSSasha Levin u16 head; 1023fdf659dSSasha Levin u32 len; 1039bd8ac5cSAsias He 104b6638c22SSasha Levin vq = param; 1059bd8ac5cSAsias He 10620f0438aSAsias He /* 10720f0438aSAsias He * The current Linux implementation polls for the buffer 10820f0438aSAsias He * to be used, rather than waiting for an interrupt. 10920f0438aSAsias He * So there is no need to inject an interrupt for the tx path. 11020f0438aSAsias He */ 11120f0438aSAsias He 1129bd8ac5cSAsias He while (virt_queue__available(vq)) { 11343835ac9SSasha Levin head = virt_queue__get_iov(vq, iov, &out, &in, kvm); 1142651ea58SSasha Levin len = term_putc_iov(iov, out, 0); 1159bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 1169bd8ac5cSAsias He } 1179bd8ac5cSAsias He 1189bd8ac5cSAsias He } 1199bd8ac5cSAsias He 120c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 1219bd8ac5cSAsias He { 122c85b4b4dSSasha Levin struct con_dev *cdev = dev; 1239bd8ac5cSAsias He 124c5ae742bSSasha Levin return ((u8 *)(&cdev->config)); 125c85b4b4dSSasha Levin } 126c85b4b4dSSasha Levin 127c85b4b4dSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 128c85b4b4dSSasha Levin { 129c85b4b4dSSasha Levin return 0; 130c85b4b4dSSasha Levin } 131c85b4b4dSSasha Levin 132c85b4b4dSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 133c85b4b4dSSasha Levin { 134c85b4b4dSSasha Levin /* Unused */ 135c85b4b4dSSasha Levin } 136c85b4b4dSSasha Levin 137c59ba304SWill Deacon static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, 138c59ba304SWill Deacon u32 pfn) 139c85b4b4dSSasha Levin { 1409bd8ac5cSAsias He struct virt_queue *queue; 1419bd8ac5cSAsias He void *p; 1429bd8ac5cSAsias He 143a2857479SCyrill Gorcunov BUG_ON(vq >= VIRTIO_CONSOLE_NUM_QUEUES); 1449bd8ac5cSAsias He 145312c62d1SSasha Levin compat__remove_message(compat_id); 146e59b1ed0SSasha Levin 147c85b4b4dSSasha Levin queue = &cdev.vqs[vq]; 148c85b4b4dSSasha Levin queue->pfn = pfn; 149e7e2950aSSasha Levin p = virtio_get_vq(kvm, queue->pfn, page_size); 1509bd8ac5cSAsias He 151c59ba304SWill Deacon vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, align); 1529bd8ac5cSAsias He 153*97bb5a9dSJonathan Austin if (vq == VIRTIO_CONSOLE_TX_QUEUE) { 154c85b4b4dSSasha Levin thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console_handle_callback, queue); 155*97bb5a9dSJonathan Austin } else if (vq == VIRTIO_CONSOLE_RX_QUEUE) { 156c85b4b4dSSasha Levin thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console__inject_interrupt_callback, queue); 157*97bb5a9dSJonathan Austin /* Tell the waiting poll thread that we're ready to go */ 158*97bb5a9dSJonathan Austin mutex_lock(&cdev.mutex); 159*97bb5a9dSJonathan Austin cdev.vq_ready = 1; 160*97bb5a9dSJonathan Austin pthread_cond_signal(&cdev.poll_cond); 161*97bb5a9dSJonathan Austin mutex_unlock(&cdev.mutex); 162*97bb5a9dSJonathan Austin } 163b6638c22SSasha Levin 164c85b4b4dSSasha Levin return 0; 1659bd8ac5cSAsias He } 1669bd8ac5cSAsias He 167c85b4b4dSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 168c85b4b4dSSasha Levin { 169c85b4b4dSSasha Levin struct con_dev *cdev = dev; 170c85b4b4dSSasha Levin 171c85b4b4dSSasha Levin thread_pool__do_job(&cdev->jobs[vq]); 172c85b4b4dSSasha Levin 173c85b4b4dSSasha Levin return 0; 174c85b4b4dSSasha Levin } 175c85b4b4dSSasha Levin 176c85b4b4dSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 177c85b4b4dSSasha Levin { 178c85b4b4dSSasha Levin struct con_dev *cdev = dev; 179c85b4b4dSSasha Levin 180c85b4b4dSSasha Levin return cdev->vqs[vq].pfn; 181c85b4b4dSSasha Levin } 182c85b4b4dSSasha Levin 183c85b4b4dSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 184c85b4b4dSSasha Levin { 185c85b4b4dSSasha Levin return VIRTIO_CONSOLE_QUEUE_SIZE; 186c85b4b4dSSasha Levin } 1879bd8ac5cSAsias He 1887aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 1897aba29c1SWill Deacon { 1907aba29c1SWill Deacon /* FIXME: dynamic */ 1917aba29c1SWill Deacon return size; 1927aba29c1SWill Deacon } 1937aba29c1SWill Deacon 1941c47ce69SSasha Levin static struct virtio_ops con_dev_virtio_ops = (struct virtio_ops) { 195c85b4b4dSSasha Levin .get_config = get_config, 196c85b4b4dSSasha Levin .get_host_features = get_host_features, 197c85b4b4dSSasha Levin .set_guest_features = set_guest_features, 198c85b4b4dSSasha Levin .init_vq = init_vq, 199c85b4b4dSSasha Levin .notify_vq = notify_vq, 200c85b4b4dSSasha Levin .get_pfn_vq = get_pfn_vq, 201c85b4b4dSSasha Levin .get_size_vq = get_size_vq, 2027aba29c1SWill Deacon .set_size_vq = set_size_vq, 203c85b4b4dSSasha Levin }; 204e59b1ed0SSasha Levin 205a3fa3f86SSasha Levin int virtio_console__init(struct kvm *kvm) 2061c47ce69SSasha Levin { 207a3fa3f86SSasha Levin if (kvm->cfg.active_console != CONSOLE_VIRTIO) 208a3fa3f86SSasha Levin return 0; 209a3fa3f86SSasha Levin 210*97bb5a9dSJonathan Austin pthread_cond_init(&cdev.poll_cond, NULL); 211*97bb5a9dSJonathan Austin 21202eca50cSAsias He virtio_init(kvm, &cdev, &cdev.vdev, &con_dev_virtio_ops, 213ae06ce71SWill Deacon VIRTIO_DEFAULT_TRANS, PCI_DEVICE_ID_VIRTIO_CONSOLE, 214ae06ce71SWill Deacon VIRTIO_ID_CONSOLE, PCI_CLASS_CONSOLE); 215d278197dSAsias He if (compat_id == -1) 21652f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-console", "CONFIG_VIRTIO_CONSOLE"); 217a3fa3f86SSasha Levin 218a3fa3f86SSasha Levin return 0; 219a3fa3f86SSasha Levin } 22049a8afd1SSasha Levin virtio_dev_init(virtio_console__init); 221a3fa3f86SSasha Levin 222a3fa3f86SSasha Levin int virtio_console__exit(struct kvm *kvm) 223a3fa3f86SSasha Levin { 224a3fa3f86SSasha Levin return 0; 2259bd8ac5cSAsias He } 22649a8afd1SSasha Levin virtio_dev_exit(virtio_console__exit); 227