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 #include "kvm/i8042.h" 11 12 #include <sys/types.h> 13 #include <sys/ioctl.h> 14 #include <inttypes.h> 15 #include <unistd.h> 16 17 #include <rfb/rfb.h> 18 19 #define VESA_QUEUE_SIZE 128 20 #define VESA_IRQ 14 21 22 /* 23 * This "6000" value is pretty much the result of experimentation 24 * It seems that around this value, things update pretty smoothly 25 */ 26 #define VESA_UPDATE_TIME 6000 27 28 static char videomem[VESA_MEM_SIZE]; 29 30 static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 31 { 32 return true; 33 } 34 35 static bool vesa_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 36 { 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[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 u16 vesa_base_addr; 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 vesa_base_addr = ioport__register(IOPORT_EMPTY, &vesa_io_ops, IOPORT_SIZE, NULL); 77 vesa_pci_device.bar[0] = vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO; 78 pci__register(&vesa_pci_device, dev); 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 server->kbdAddEvent = kbd_handle_key; 104 server->ptrAddEvent = kbd_handle_ptr; 105 rfbInitServer(server); 106 107 while (rfbIsActive(server)) { 108 rfbMarkRectAsModified(server, 0, 0, VESA_WIDTH, VESA_HEIGHT); 109 rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME); 110 } 111 return NULL; 112 } 113