19bd8ac5cSAsias He #include "kvm/console-virtio.h" 29bd8ac5cSAsias He #include "kvm/virtio_pci.h" 39bd8ac5cSAsias He #include "kvm/disk-image.h" 4*39d6af07SAsias He #include "kvm/virtio.h" 59bd8ac5cSAsias He #include "kvm/ioport.h" 69bd8ac5cSAsias He #include "kvm/util.h" 79bd8ac5cSAsias He #include "kvm/term.h" 89bd8ac5cSAsias He #include "kvm/kvm.h" 99bd8ac5cSAsias He #include "kvm/pci.h" 109bd8ac5cSAsias He 119bd8ac5cSAsias He #include <linux/virtio_console.h> 129bd8ac5cSAsias He #include <linux/virtio_ring.h> 139bd8ac5cSAsias He #include <linux/virtio_blk.h> 149bd8ac5cSAsias He 159bd8ac5cSAsias He #include <sys/uio.h> 169bd8ac5cSAsias He #include <sys/types.h> 179bd8ac5cSAsias He #include <sys/stat.h> 189bd8ac5cSAsias He #include <inttypes.h> 199bd8ac5cSAsias He #include <termios.h> 209bd8ac5cSAsias He #include <assert.h> 219bd8ac5cSAsias He #include <unistd.h> 229bd8ac5cSAsias He #include <fcntl.h> 239bd8ac5cSAsias He 249bd8ac5cSAsias He #define VIRTIO_CONSOLE_IRQ 14 259bd8ac5cSAsias He #define VIRTIO_CONSOLE_QUEUE_SIZE 128 269bd8ac5cSAsias He #define VIRTIO_CONSOLE_NUM_QUEUES 2 279bd8ac5cSAsias He #define VIRTIO_CONSOLE_RX_QUEUE 0 289bd8ac5cSAsias He #define VIRTIO_CONSOLE_TX_QUEUE 1 299bd8ac5cSAsias He #define PCI_VIRTIO_CONSOLE_DEVNUM 2 309bd8ac5cSAsias He 319bd8ac5cSAsias He struct console_device { 329bd8ac5cSAsias He struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES]; 339bd8ac5cSAsias He struct virtio_console_config console_config; 349bd8ac5cSAsias He uint32_t host_features; 359bd8ac5cSAsias He uint32_t guest_features; 369bd8ac5cSAsias He uint16_t config_vector; 379bd8ac5cSAsias He uint8_t status; 389bd8ac5cSAsias He uint16_t queue_selector; 399bd8ac5cSAsias He }; 409bd8ac5cSAsias He 419bd8ac5cSAsias He static struct console_device console_device = { 429bd8ac5cSAsias He .console_config = { 439bd8ac5cSAsias He .cols = 80, 449bd8ac5cSAsias He .rows = 24, 459bd8ac5cSAsias He .max_nr_ports = 1, 469bd8ac5cSAsias He }, 479bd8ac5cSAsias He 489bd8ac5cSAsias He .host_features = 0, 499bd8ac5cSAsias He }; 509bd8ac5cSAsias He 519bd8ac5cSAsias He /* 529bd8ac5cSAsias He * Interrupts are injected for hvc0 only. 539bd8ac5cSAsias He */ 549bd8ac5cSAsias He void virtio_console__inject_interrupt(struct kvm *self) 559bd8ac5cSAsias He { 569bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 579bd8ac5cSAsias He struct virt_queue *vq; 589bd8ac5cSAsias He uint16_t out, in; 599bd8ac5cSAsias He uint16_t head; 609bd8ac5cSAsias He int len; 619bd8ac5cSAsias He 629bd8ac5cSAsias He vq = &console_device.vqs[VIRTIO_CONSOLE_RX_QUEUE]; 639bd8ac5cSAsias He 649bd8ac5cSAsias He if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) { 659bd8ac5cSAsias He head = virt_queue__get_iov(vq, iov, &out, &in, self); 669bd8ac5cSAsias He len = term_getc_iov(CONSOLE_VIRTIO, iov, in); 679bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 689bd8ac5cSAsias He kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1); 699bd8ac5cSAsias He } 709bd8ac5cSAsias He } 719bd8ac5cSAsias He 729bd8ac5cSAsias He static bool virtio_console_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count) 739bd8ac5cSAsias He { 749bd8ac5cSAsias He uint8_t *config_space = (uint8_t *) &console_device.console_config; 759bd8ac5cSAsias He 769bd8ac5cSAsias He if (size != 1 || count != 1) 779bd8ac5cSAsias He return false; 789bd8ac5cSAsias He 799bd8ac5cSAsias He if ((offset - VIRTIO_PCI_CONFIG_NOMSI) > sizeof(struct virtio_console_config)) 809bd8ac5cSAsias He error("config offset is too big: %li", offset - VIRTIO_PCI_CONFIG_NOMSI); 819bd8ac5cSAsias He 829bd8ac5cSAsias He ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 839bd8ac5cSAsias He 849bd8ac5cSAsias He return true; 859bd8ac5cSAsias He } 869bd8ac5cSAsias He 879bd8ac5cSAsias He static bool virtio_console_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 889bd8ac5cSAsias He { 899bd8ac5cSAsias He unsigned long offset = port - IOPORT_VIRTIO_CONSOLE; 909bd8ac5cSAsias He 919bd8ac5cSAsias He switch (offset) { 929bd8ac5cSAsias He case VIRTIO_PCI_HOST_FEATURES: 939bd8ac5cSAsias He ioport__write32(data, console_device.host_features); 949bd8ac5cSAsias He break; 959bd8ac5cSAsias He case VIRTIO_PCI_GUEST_FEATURES: 969bd8ac5cSAsias He return false; 979bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_PFN: 989bd8ac5cSAsias He ioport__write32(data, console_device.vqs[console_device.queue_selector].pfn); 999bd8ac5cSAsias He break; 1009bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_NUM: 1019bd8ac5cSAsias He ioport__write16(data, VIRTIO_CONSOLE_QUEUE_SIZE); 1029bd8ac5cSAsias He break; 1039bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_SEL: 1049bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_NOTIFY: 1059bd8ac5cSAsias He return false; 1069bd8ac5cSAsias He case VIRTIO_PCI_STATUS: 1079bd8ac5cSAsias He ioport__write8(data, console_device.status); 1089bd8ac5cSAsias He break; 1099bd8ac5cSAsias He case VIRTIO_PCI_ISR: 1109bd8ac5cSAsias He ioport__write8(data, 0x1); 1119bd8ac5cSAsias He kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 0); 1129bd8ac5cSAsias He break; 1139bd8ac5cSAsias He case VIRTIO_MSI_CONFIG_VECTOR: 1149bd8ac5cSAsias He ioport__write16(data, console_device.config_vector); 1159bd8ac5cSAsias He break; 1169bd8ac5cSAsias He default: 1179bd8ac5cSAsias He return virtio_console_pci_io_device_specific_in(data, offset, size, count); 1189bd8ac5cSAsias He }; 1199bd8ac5cSAsias He 1209bd8ac5cSAsias He return true; 1219bd8ac5cSAsias He } 1229bd8ac5cSAsias He 1239bd8ac5cSAsias He static void virtio_console_handle_callback(struct kvm *self, uint16_t queue_index) 1249bd8ac5cSAsias He { 1259bd8ac5cSAsias He struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE]; 1269bd8ac5cSAsias He struct virt_queue *vq; 1279bd8ac5cSAsias He uint16_t out, in; 1289bd8ac5cSAsias He uint16_t head; 1299bd8ac5cSAsias He uint32_t len; 1309bd8ac5cSAsias He 1319bd8ac5cSAsias He vq = &console_device.vqs[queue_index]; 1329bd8ac5cSAsias He 1339bd8ac5cSAsias He if (queue_index == VIRTIO_CONSOLE_TX_QUEUE) { 1349bd8ac5cSAsias He 1359bd8ac5cSAsias He while (virt_queue__available(vq)) { 1369bd8ac5cSAsias He head = virt_queue__get_iov(vq, iov, &out, &in, self); 1379bd8ac5cSAsias He len = term_putc_iov(CONSOLE_VIRTIO, iov, out); 1389bd8ac5cSAsias He virt_queue__set_used_elem(vq, head, len); 1399bd8ac5cSAsias He } 1409bd8ac5cSAsias He 1419bd8ac5cSAsias He kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1); 1429bd8ac5cSAsias He } 1439bd8ac5cSAsias He } 1449bd8ac5cSAsias He 1459bd8ac5cSAsias He static bool virtio_console_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 1469bd8ac5cSAsias He { 1479bd8ac5cSAsias He unsigned long offset = port - IOPORT_VIRTIO_CONSOLE; 1489bd8ac5cSAsias He 1499bd8ac5cSAsias He switch (offset) { 1509bd8ac5cSAsias He case VIRTIO_PCI_GUEST_FEATURES: 1519bd8ac5cSAsias He console_device.guest_features = ioport__read32(data); 1529bd8ac5cSAsias He break; 1539bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_PFN: { 1549bd8ac5cSAsias He struct virt_queue *queue; 1559bd8ac5cSAsias He void *p; 1569bd8ac5cSAsias He 1579bd8ac5cSAsias He assert(console_device.queue_selector < VIRTIO_CONSOLE_NUM_QUEUES); 1589bd8ac5cSAsias He 1599bd8ac5cSAsias He queue = &console_device.vqs[console_device.queue_selector]; 1609bd8ac5cSAsias He queue->pfn = ioport__read32(data); 1619bd8ac5cSAsias He p = guest_flat_to_host(self, queue->pfn << 12); 1629bd8ac5cSAsias He 1639bd8ac5cSAsias He vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, 4096); 1649bd8ac5cSAsias He 1659bd8ac5cSAsias He break; 1669bd8ac5cSAsias He } 1679bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_SEL: 1689bd8ac5cSAsias He console_device.queue_selector = ioport__read16(data); 1699bd8ac5cSAsias He break; 1709bd8ac5cSAsias He case VIRTIO_PCI_QUEUE_NOTIFY: { 1719bd8ac5cSAsias He uint16_t queue_index; 1729bd8ac5cSAsias He queue_index = ioport__read16(data); 1739bd8ac5cSAsias He virtio_console_handle_callback(self, queue_index); 1749bd8ac5cSAsias He break; 1759bd8ac5cSAsias He } 1769bd8ac5cSAsias He case VIRTIO_PCI_STATUS: 1779bd8ac5cSAsias He console_device.status = ioport__read8(data); 1789bd8ac5cSAsias He break; 1799bd8ac5cSAsias He case VIRTIO_MSI_CONFIG_VECTOR: 1809bd8ac5cSAsias He console_device.config_vector = VIRTIO_MSI_NO_VECTOR; 1819bd8ac5cSAsias He break; 1829bd8ac5cSAsias He case VIRTIO_MSI_QUEUE_VECTOR: 1839bd8ac5cSAsias He break; 1849bd8ac5cSAsias He default: 1859bd8ac5cSAsias He return false; 1869bd8ac5cSAsias He }; 1879bd8ac5cSAsias He 1889bd8ac5cSAsias He return true; 1899bd8ac5cSAsias He } 1909bd8ac5cSAsias He 1919bd8ac5cSAsias He static struct ioport_operations virtio_console_io_ops = { 1929bd8ac5cSAsias He .io_in = virtio_console_pci_io_in, 1939bd8ac5cSAsias He .io_out = virtio_console_pci_io_out, 1949bd8ac5cSAsias He }; 1959bd8ac5cSAsias He 1969bd8ac5cSAsias He #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 1979bd8ac5cSAsias He #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1002 1989bd8ac5cSAsias He #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 1999bd8ac5cSAsias He #define PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE 0x0003 2009bd8ac5cSAsias He 2019bd8ac5cSAsias He static struct pci_device_header virtio_console_pci_device = { 2029bd8ac5cSAsias He .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 2039bd8ac5cSAsias He .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE, 2049bd8ac5cSAsias He .header_type = PCI_HEADER_TYPE_NORMAL, 2059bd8ac5cSAsias He .revision_id = 0, 2069bd8ac5cSAsias He .class = (0x07 << 8) | (0x80 << 4) | (0x0 << 0), 2079bd8ac5cSAsias He .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 2089bd8ac5cSAsias He .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE, 2099bd8ac5cSAsias He .bar[0] = IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO, 2109bd8ac5cSAsias He .irq_pin = 3, 2119bd8ac5cSAsias He .irq_line = VIRTIO_CONSOLE_IRQ, 2129bd8ac5cSAsias He }; 2139bd8ac5cSAsias He 2149bd8ac5cSAsias He void virtio_console__init(struct kvm *self) 2159bd8ac5cSAsias He { 2169bd8ac5cSAsias He pci__register(&virtio_console_pci_device, PCI_VIRTIO_CONSOLE_DEVNUM); 2179bd8ac5cSAsias He ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE); 2189bd8ac5cSAsias He } 219