xref: /kvmtool/hw/vesa.c (revision 5d6dd281f4d94e7ecdcda49cc1b40479029e07b9)
1 #include "kvm/vesa.h"
2 
3 #include "kvm/devices.h"
4 #include "kvm/virtio-pci-dev.h"
5 #include "kvm/framebuffer.h"
6 #include "kvm/kvm-cpu.h"
7 #include "kvm/ioport.h"
8 #include "kvm/util.h"
9 #include "kvm/irq.h"
10 #include "kvm/kvm.h"
11 #include "kvm/pci.h"
12 
13 #include <linux/byteorder.h>
14 #include <sys/mman.h>
15 #include <linux/err.h>
16 #include <sys/types.h>
17 #include <sys/ioctl.h>
18 #include <inttypes.h>
19 #include <unistd.h>
20 
21 static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
22 {
23 	return true;
24 }
25 
26 static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
27 {
28 	return true;
29 }
30 
31 static struct ioport_operations vesa_io_ops = {
32 	.io_in			= vesa_pci_io_in,
33 	.io_out			= vesa_pci_io_out,
34 };
35 
36 static struct pci_device_header vesa_pci_device = {
37 	.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
38 	.device_id		= cpu_to_le16(PCI_DEVICE_ID_VESA),
39 	.header_type		= PCI_HEADER_TYPE_NORMAL,
40 	.revision_id		= 0,
41 	.class[2]		= 0x03,
42 	.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
43 	.subsys_id		= cpu_to_le16(PCI_SUBSYSTEM_ID_VESA),
44 	.bar[1]			= cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY),
45 	.bar_size[1]		= VESA_MEM_SIZE,
46 };
47 
48 static struct device_header vesa_device = {
49 	.bus_type	= DEVICE_BUS_PCI,
50 	.data		= &vesa_pci_device,
51 };
52 
53 static struct framebuffer vesafb;
54 
55 struct framebuffer *vesa__init(struct kvm *kvm)
56 {
57 	u16 vesa_base_addr;
58 	char *mem;
59 	int r;
60 
61 	BUILD_BUG_ON(!is_power_of_two(VESA_MEM_SIZE));
62 	BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT);
63 
64 	if (!kvm->cfg.vnc && !kvm->cfg.sdl && !kvm->cfg.gtk)
65 		return NULL;
66 	vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE);
67 	r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL);
68 	if (r < 0)
69 		goto out_error;
70 
71 	vesa_pci_device.bar[0]		= cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
72 	r = device__register(&vesa_device);
73 	if (r < 0)
74 		goto unregister_ioport;
75 
76 	mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
77 	if (mem == MAP_FAILED) {
78 		r = -errno;
79 		goto unregister_device;
80 	}
81 
82 	r = kvm__register_dev_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
83 	if (r < 0)
84 		goto unmap_dev;
85 
86 	vesafb = (struct framebuffer) {
87 		.width			= VESA_WIDTH,
88 		.height			= VESA_HEIGHT,
89 		.depth			= VESA_BPP,
90 		.mem			= mem,
91 		.mem_addr		= VESA_MEM_ADDR,
92 		.mem_size		= VESA_MEM_SIZE,
93 		.kvm			= kvm,
94 	};
95 	return fb__register(&vesafb);
96 
97 unmap_dev:
98 	munmap(mem, VESA_MEM_SIZE);
99 unregister_device:
100 	device__unregister(&vesa_device);
101 unregister_ioport:
102 	ioport__unregister(kvm, vesa_base_addr);
103 out_error:
104 	return ERR_PTR(r);
105 }
106