xref: /kvmtool/hw/vesa.c (revision 5a8e4f25dd7b32228ff214b5d5a68a27d96c9a6c)
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 struct pci_device_header vesa_pci_device = {
22 	.vendor_id	= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
23 	.device_id	= cpu_to_le16(PCI_DEVICE_ID_VESA),
24 	.header_type	= PCI_HEADER_TYPE_NORMAL,
25 	.revision_id	= 0,
26 	.class[2]	= 0x03,
27 	.subsys_vendor_id = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
28 	.subsys_id	= cpu_to_le16(PCI_SUBSYSTEM_ID_VESA),
29 	.bar[1]		= cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY),
30 	.bar_size[1]	= VESA_MEM_SIZE,
31 };
32 
33 static struct device_header vesa_device = {
34 	.bus_type	= DEVICE_BUS_PCI,
35 	.data		= &vesa_pci_device,
36 };
37 
38 static struct framebuffer vesafb = {
39 	.width		= VESA_WIDTH,
40 	.height		= VESA_HEIGHT,
41 	.depth		= VESA_BPP,
42 	.mem_addr	= VESA_MEM_ADDR,
43 	.mem_size	= VESA_MEM_SIZE,
44 };
45 
46 static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
47 {
48 	return true;
49 }
50 
51 static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
52 {
53 	return true;
54 }
55 
56 static struct ioport_operations vesa_io_ops = {
57 	.io_in			= vesa_pci_io_in,
58 	.io_out			= vesa_pci_io_out,
59 };
60 
61 static int vesa__bar_activate(struct kvm *kvm, struct pci_device_header *pci_hdr,
62 			      int bar_num, void *data)
63 {
64 	/* We don't support remapping of the framebuffer. */
65 	return 0;
66 }
67 
68 static int vesa__bar_deactivate(struct kvm *kvm, struct pci_device_header *pci_hdr,
69 				int bar_num, void *data)
70 {
71 	/* We don't support remapping of the framebuffer. */
72 	return -EINVAL;
73 }
74 
75 struct framebuffer *vesa__init(struct kvm *kvm)
76 {
77 	u16 vesa_base_addr;
78 	char *mem;
79 	int r;
80 
81 	BUILD_BUG_ON(!is_power_of_two(VESA_MEM_SIZE));
82 	BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT);
83 
84 	vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE);
85 	r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL);
86 	if (r < 0)
87 		goto out_error;
88 
89 	vesa_pci_device.bar[0]		= cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
90 	vesa_pci_device.bar_size[0]	= PCI_IO_SIZE;
91 	r = pci__register_bar_regions(kvm, &vesa_pci_device, vesa__bar_activate,
92 				      vesa__bar_deactivate, NULL);
93 	if (r < 0)
94 		goto unregister_ioport;
95 
96 	r = device__register(&vesa_device);
97 	if (r < 0)
98 		goto unregister_ioport;
99 
100 	mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
101 	if (mem == MAP_FAILED) {
102 		r = -errno;
103 		goto unregister_device;
104 	}
105 
106 	r = kvm__register_dev_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
107 	if (r < 0)
108 		goto unmap_dev;
109 
110 	vesafb.mem = mem;
111 	vesafb.kvm = kvm;
112 	return fb__register(&vesafb);
113 
114 unmap_dev:
115 	munmap(mem, VESA_MEM_SIZE);
116 unregister_device:
117 	device__unregister(&vesa_device);
118 unregister_ioport:
119 	ioport__unregister(kvm, vesa_base_addr);
120 out_error:
121 	return ERR_PTR(r);
122 }
123