1b025083dSJohn Floren #include "kvm/vesa.h" 2*de960f08SPekka Enberg 3*de960f08SPekka Enberg #include "kvm/virtio-pci-dev.h" 4*de960f08SPekka Enberg #include "kvm/kvm-cpu.h" 5b025083dSJohn Floren #include "kvm/ioport.h" 6b025083dSJohn Floren #include "kvm/util.h" 7*de960f08SPekka Enberg #include "kvm/irq.h" 8b025083dSJohn Floren #include "kvm/kvm.h" 9b025083dSJohn Floren #include "kvm/pci.h" 10b025083dSJohn Floren 11b025083dSJohn Floren #include <sys/types.h> 12b025083dSJohn Floren #include <sys/ioctl.h> 13b025083dSJohn Floren #include <inttypes.h> 14b025083dSJohn Floren #include <unistd.h> 15b025083dSJohn Floren 16*de960f08SPekka Enberg #include <rfb/rfb.h> 17*de960f08SPekka Enberg 18b025083dSJohn Floren #define VESA_QUEUE_SIZE 128 19b025083dSJohn Floren #define VESA_IRQ 14 20b025083dSJohn Floren 21b025083dSJohn Floren /* 22b025083dSJohn Floren * This "6000" value is pretty much the result of experimentation 23b025083dSJohn Floren * It seems that around this value, things update pretty smoothly 24b025083dSJohn Floren */ 25b025083dSJohn Floren #define VESA_UPDATE_TIME 6000 26b025083dSJohn Floren 27*de960f08SPekka Enberg static char videomem[VESA_MEM_SIZE]; 28b025083dSJohn Floren 29b025083dSJohn Floren static bool vesa_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count) 30b025083dSJohn Floren { 31b025083dSJohn Floren return true; 32b025083dSJohn Floren } 33b025083dSJohn Floren 34b025083dSJohn Floren static bool vesa_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count) 35b025083dSJohn Floren { 36b025083dSJohn Floren return true; 37b025083dSJohn Floren } 38b025083dSJohn Floren 39b025083dSJohn Floren static struct ioport_operations vesa_io_ops = { 40b025083dSJohn Floren .io_in = vesa_pci_io_in, 41b025083dSJohn Floren .io_out = vesa_pci_io_out, 42b025083dSJohn Floren }; 43b025083dSJohn Floren 44b025083dSJohn Floren static struct pci_device_header vesa_pci_device = { 45b025083dSJohn Floren .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 46b025083dSJohn Floren .device_id = PCI_DEVICE_ID_VESA, 47b025083dSJohn Floren .header_type = PCI_HEADER_TYPE_NORMAL, 48b025083dSJohn Floren .revision_id = 0, 49b025083dSJohn Floren .class = 0x030000, 50b025083dSJohn Floren .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 51b025083dSJohn Floren .subsys_id = PCI_SUBSYSTEM_ID_VESA, 52b025083dSJohn Floren .bar[0] = IOPORT_VESA | PCI_BASE_ADDRESS_SPACE_IO, 53b025083dSJohn Floren .bar[1] = VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY, 54b025083dSJohn Floren }; 55b025083dSJohn Floren 56b025083dSJohn Floren 57b025083dSJohn Floren void vesa_mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write) 58b025083dSJohn Floren { 59*de960f08SPekka Enberg if (!is_write) 60b025083dSJohn Floren return; 61*de960f08SPekka Enberg 62*de960f08SPekka Enberg memcpy(&videomem[addr - VESA_MEM_ADDR], data, len); 63b025083dSJohn Floren } 64b025083dSJohn Floren 65b025083dSJohn Floren void vesa__init(struct kvm *kvm) 66b025083dSJohn Floren { 67b025083dSJohn Floren u8 dev, line, pin; 68b025083dSJohn Floren pthread_t thread; 69b025083dSJohn Floren 70b025083dSJohn Floren if (irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line) < 0) 71b025083dSJohn Floren return; 72b025083dSJohn Floren 73b025083dSJohn Floren vesa_pci_device.irq_pin = pin; 74b025083dSJohn Floren vesa_pci_device.irq_line = line; 75*de960f08SPekka Enberg 76b025083dSJohn Floren pci__register(&vesa_pci_device, dev); 77*de960f08SPekka Enberg 78b025083dSJohn Floren ioport__register(IOPORT_VESA, &vesa_io_ops, IOPORT_VESA_SIZE); 79b025083dSJohn Floren 80b025083dSJohn Floren kvm__register_mmio(VESA_MEM_ADDR, VESA_MEM_SIZE, &vesa_mmio_callback); 81*de960f08SPekka Enberg 82b025083dSJohn Floren pthread_create(&thread, NULL, vesa__dovnc, kvm); 83b025083dSJohn Floren } 84b025083dSJohn Floren 85b025083dSJohn Floren /* 86b025083dSJohn Floren * This starts a VNC server to display the framebuffer. 87b025083dSJohn Floren * It's not altogether clear this belongs here rather than in kvm-run.c 88b025083dSJohn Floren */ 89b025083dSJohn Floren void *vesa__dovnc(void *v) 90b025083dSJohn Floren { 91b025083dSJohn Floren /* 92b025083dSJohn Floren * Make a fake argc and argv because the getscreen function 93b025083dSJohn Floren * seems to want it. 94b025083dSJohn Floren */ 95*de960f08SPekka Enberg char argv[1][1] = {{0}}; 96*de960f08SPekka Enberg int argc = 1; 97*de960f08SPekka Enberg 98b025083dSJohn Floren rfbScreenInfoPtr server; 99b025083dSJohn Floren 100*de960f08SPekka Enberg server = rfbGetScreen(&argc, (char **) argv, VESA_WIDTH, VESA_HEIGHT, 8, 3, 4); 101*de960f08SPekka Enberg server->frameBuffer = videomem; 102b025083dSJohn Floren server->alwaysShared = TRUE; 103b025083dSJohn Floren rfbInitServer(server); 104b025083dSJohn Floren 105b025083dSJohn Floren while (rfbIsActive(server)) { 106b025083dSJohn Floren rfbMarkRectAsModified(server, 0, 0, VESA_WIDTH, VESA_HEIGHT); 107b025083dSJohn Floren rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME); 108b025083dSJohn Floren } 109b025083dSJohn Floren return NULL; 110b025083dSJohn Floren } 111