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