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" 14*c85b4b4dSSasha Levin #include "kvm/virtio-pci.h" 159bd8ac5cSAsias He 169bd8ac5cSAsias He #include <linux/virtio_console.h> 179bd8ac5cSAsias He #include <linux/virtio_ring.h> 189bd8ac5cSAsias He #include <linux/virtio_blk.h> 199bd8ac5cSAsias He 209bd8ac5cSAsias He #include <sys/uio.h> 219bd8ac5cSAsias He #include <sys/types.h> 229bd8ac5cSAsias He #include <sys/stat.h> 239bd8ac5cSAsias He #include <termios.h> 249bd8ac5cSAsias He #include <assert.h> 259bd8ac5cSAsias He #include <unistd.h> 269bd8ac5cSAsias He #include <fcntl.h> 279bd8ac5cSAsias He 289bd8ac5cSAsias He #define VIRTIO_CONSOLE_QUEUE_SIZE 128 299bd8ac5cSAsias He #define VIRTIO_CONSOLE_NUM_QUEUES 2 309bd8ac5cSAsias He #define VIRTIO_CONSOLE_RX_QUEUE 0 319bd8ac5cSAsias He #define VIRTIO_CONSOLE_TX_QUEUE 1 329bd8ac5cSAsias He 33a643306eSSasha Levin struct con_dev { 347512639bSAsias He pthread_mutex_t mutex; 357512639bSAsias He 36*c85b4b4dSSasha Levin struct virtio_pci vpci; 379bd8ac5cSAsias He struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES]; 38*c85b4b4dSSasha Levin struct virtio_console_config config; 39*c85b4b4dSSasha Levin u32 features; 40e59b1ed0SSasha Levin int compat_id; 41b6638c22SSasha Levin 42df0c7f57SSasha Levin struct thread_pool__job jobs[VIRTIO_CONSOLE_NUM_QUEUES]; 439bd8ac5cSAsias He }; 449bd8ac5cSAsias He 45a643306eSSasha Levin static struct con_dev cdev = { 467512639bSAsias He .mutex = PTHREAD_MUTEX_INITIALIZER, 477512639bSAsias He 48*c85b4b4dSSasha Levin .config = { 499bd8ac5cSAsias He .cols = 80, 509bd8ac5cSAsias He .rows = 24, 519bd8ac5cSAsias He .max_nr_ports = 1, 529bd8ac5cSAsias He }, 539bd8ac5cSAsias He }; 549bd8ac5cSAsias He 559bd8ac5cSAsias He /* 569bd8ac5cSAsias He * Interrupts are injected for hvc0 only. 579bd8ac5cSAsias He */ 5843835ac9SSasha Levin static void virtio_console__inject_interrupt_callback(struct kvm *kvm, void *param) 599bd8ac5cSAsias He { 609bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 619bd8ac5cSAsias He struct virt_queue *vq; 623fdf659dSSasha Levin u16 out, in; 633fdf659dSSasha Levin u16 head; 649bd8ac5cSAsias He int len; 659bd8ac5cSAsias He 66a643306eSSasha Levin mutex_lock(&cdev.mutex); 677512639bSAsias He 68b6638c22SSasha Levin vq = param; 699bd8ac5cSAsias He 709bd8ac5cSAsias He if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) { 7143835ac9SSasha Levin head = virt_queue__get_iov(vq, iov, &out, &in, kvm); 729bd8ac5cSAsias He len = term_getc_iov(CONSOLE_VIRTIO, iov, in); 739bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 74*c85b4b4dSSasha Levin virtio_pci__signal_vq(kvm, &cdev.vpci, vq - cdev.vqs); 759bd8ac5cSAsias He } 767512639bSAsias He 77a643306eSSasha Levin mutex_unlock(&cdev.mutex); 789bd8ac5cSAsias He } 799bd8ac5cSAsias He 8043835ac9SSasha Levin void virtio_console__inject_interrupt(struct kvm *kvm) 81b6638c22SSasha Levin { 82df0c7f57SSasha Levin thread_pool__do_job(&cdev.jobs[VIRTIO_CONSOLE_RX_QUEUE]); 83b6638c22SSasha Levin } 84b6638c22SSasha Levin 8543835ac9SSasha Levin static void virtio_console_handle_callback(struct kvm *kvm, void *param) 869bd8ac5cSAsias He { 879bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 889bd8ac5cSAsias He struct virt_queue *vq; 893fdf659dSSasha Levin u16 out, in; 903fdf659dSSasha Levin u16 head; 913fdf659dSSasha Levin u32 len; 929bd8ac5cSAsias He 93b6638c22SSasha Levin vq = param; 949bd8ac5cSAsias He 9520f0438aSAsias He /* 9620f0438aSAsias He * The current Linux implementation polls for the buffer 9720f0438aSAsias He * to be used, rather than waiting for an interrupt. 9820f0438aSAsias He * So there is no need to inject an interrupt for the tx path. 9920f0438aSAsias He */ 10020f0438aSAsias He 1019bd8ac5cSAsias He while (virt_queue__available(vq)) { 10243835ac9SSasha Levin head = virt_queue__get_iov(vq, iov, &out, &in, kvm); 1039bd8ac5cSAsias He len = term_putc_iov(CONSOLE_VIRTIO, iov, out); 1049bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 1059bd8ac5cSAsias He } 1069bd8ac5cSAsias He 1079bd8ac5cSAsias He } 1089bd8ac5cSAsias He 109*c85b4b4dSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 1109bd8ac5cSAsias He { 111*c85b4b4dSSasha Levin struct con_dev *cdev = dev; 1129bd8ac5cSAsias He 113*c85b4b4dSSasha Levin ((u8 *)(&cdev->config))[offset] = data; 114*c85b4b4dSSasha Levin } 115e147d838SAsias He 116*c85b4b4dSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 117*c85b4b4dSSasha Levin { 118*c85b4b4dSSasha Levin struct con_dev *cdev = dev; 119*c85b4b4dSSasha Levin 120*c85b4b4dSSasha Levin return ((u8 *)(&cdev->config))[offset]; 121*c85b4b4dSSasha Levin } 122*c85b4b4dSSasha Levin 123*c85b4b4dSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 124*c85b4b4dSSasha Levin { 125*c85b4b4dSSasha Levin return 0; 126*c85b4b4dSSasha Levin } 127*c85b4b4dSSasha Levin 128*c85b4b4dSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 129*c85b4b4dSSasha Levin { 130*c85b4b4dSSasha Levin /* Unused */ 131*c85b4b4dSSasha Levin } 132*c85b4b4dSSasha Levin 133*c85b4b4dSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 134*c85b4b4dSSasha Levin { 1359bd8ac5cSAsias He struct virt_queue *queue; 1369bd8ac5cSAsias He void *p; 1379bd8ac5cSAsias He 138*c85b4b4dSSasha Levin assert(vq < VIRTIO_CONSOLE_NUM_QUEUES); 1399bd8ac5cSAsias He 140e59b1ed0SSasha Levin compat__remove_message(cdev.compat_id); 141e59b1ed0SSasha Levin 142*c85b4b4dSSasha Levin queue = &cdev.vqs[vq]; 143*c85b4b4dSSasha Levin queue->pfn = pfn; 14443835ac9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 1459bd8ac5cSAsias He 146b8f43678SSasha Levin vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 1479bd8ac5cSAsias He 148*c85b4b4dSSasha Levin if (vq == VIRTIO_CONSOLE_TX_QUEUE) 149*c85b4b4dSSasha Levin thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console_handle_callback, queue); 150*c85b4b4dSSasha Levin else if (vq == VIRTIO_CONSOLE_RX_QUEUE) 151*c85b4b4dSSasha Levin thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console__inject_interrupt_callback, queue); 152b6638c22SSasha Levin 153*c85b4b4dSSasha Levin return 0; 1549bd8ac5cSAsias He } 1559bd8ac5cSAsias He 156*c85b4b4dSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 157*c85b4b4dSSasha Levin { 158*c85b4b4dSSasha Levin struct con_dev *cdev = dev; 159*c85b4b4dSSasha Levin 160*c85b4b4dSSasha Levin thread_pool__do_job(&cdev->jobs[vq]); 161*c85b4b4dSSasha Levin 162*c85b4b4dSSasha Levin return 0; 163*c85b4b4dSSasha Levin } 164*c85b4b4dSSasha Levin 165*c85b4b4dSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 166*c85b4b4dSSasha Levin { 167*c85b4b4dSSasha Levin struct con_dev *cdev = dev; 168*c85b4b4dSSasha Levin 169*c85b4b4dSSasha Levin return cdev->vqs[vq].pfn; 170*c85b4b4dSSasha Levin } 171*c85b4b4dSSasha Levin 172*c85b4b4dSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 173*c85b4b4dSSasha Levin { 174*c85b4b4dSSasha Levin return VIRTIO_CONSOLE_QUEUE_SIZE; 175*c85b4b4dSSasha Levin } 1769bd8ac5cSAsias He 17743835ac9SSasha Levin void virtio_console__init(struct kvm *kvm) 1789bd8ac5cSAsias He { 179*c85b4b4dSSasha Levin virtio_pci__init(kvm, &cdev.vpci, &cdev, PCI_DEVICE_ID_VIRTIO_CONSOLE, VIRTIO_ID_CONSOLE); 180*c85b4b4dSSasha Levin cdev.vpci.ops = (struct virtio_pci_ops) { 181*c85b4b4dSSasha Levin .set_config = set_config, 182*c85b4b4dSSasha Levin .get_config = get_config, 183*c85b4b4dSSasha Levin .get_host_features = get_host_features, 184*c85b4b4dSSasha Levin .set_guest_features = set_guest_features, 185*c85b4b4dSSasha Levin .init_vq = init_vq, 186*c85b4b4dSSasha Levin .notify_vq = notify_vq, 187*c85b4b4dSSasha Levin .get_pfn_vq = get_pfn_vq, 188*c85b4b4dSSasha Levin .get_size_vq = get_size_vq, 189*c85b4b4dSSasha Levin }; 190e59b1ed0SSasha Levin 191e59b1ed0SSasha Levin cdev.compat_id = compat__add_message("virtio-console device was not detected", 192e59b1ed0SSasha Levin "While you have requested a virtio-console device, " 193e59b1ed0SSasha Levin "the guest kernel didn't seem to detect it.\n" 194e59b1ed0SSasha Levin "Please make sure that the kernel was compiled" 195e59b1ed0SSasha Levin "with CONFIG_VIRTIO_CONSOLE."); 1969bd8ac5cSAsias He } 197