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