xref: /kvmtool/hw/vesa.c (revision b025083d4b2db30bd2fedd263a1470c9a02d9272)
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