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