xref: /kvmtool/hw/vesa.c (revision 5d6dd281f4d94e7ecdcda49cc1b40479029e07b9)
1b025083dSJohn Floren #include "kvm/vesa.h"
2de960f08SPekka Enberg 
321ff329dSWill Deacon #include "kvm/devices.h"
4de960f08SPekka Enberg #include "kvm/virtio-pci-dev.h"
5aba1efa5SPekka Enberg #include "kvm/framebuffer.h"
6de960f08SPekka Enberg #include "kvm/kvm-cpu.h"
7b025083dSJohn Floren #include "kvm/ioport.h"
8b025083dSJohn Floren #include "kvm/util.h"
9de960f08SPekka Enberg #include "kvm/irq.h"
10b025083dSJohn Floren #include "kvm/kvm.h"
11b025083dSJohn Floren #include "kvm/pci.h"
1248d9e01aSSasha Levin 
13aa73be70SMatt Evans #include <linux/byteorder.h>
1496feb589SPekka Enberg #include <sys/mman.h>
1548d9e01aSSasha Levin #include <linux/err.h>
16b025083dSJohn Floren #include <sys/types.h>
17b025083dSJohn Floren #include <sys/ioctl.h>
18b025083dSJohn Floren #include <inttypes.h>
19b025083dSJohn Floren #include <unistd.h>
20b025083dSJohn Floren 
214123ca55SMarc Zyngier static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
22b025083dSJohn Floren {
23b025083dSJohn Floren 	return true;
24b025083dSJohn Floren }
25b025083dSJohn Floren 
264123ca55SMarc Zyngier static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
27b025083dSJohn Floren {
28b025083dSJohn Floren 	return true;
29b025083dSJohn Floren }
30b025083dSJohn Floren 
31b025083dSJohn Floren static struct ioport_operations vesa_io_ops = {
32b025083dSJohn Floren 	.io_in			= vesa_pci_io_in,
33b025083dSJohn Floren 	.io_out			= vesa_pci_io_out,
34b025083dSJohn Floren };
35b025083dSJohn Floren 
36b025083dSJohn Floren static struct pci_device_header vesa_pci_device = {
37aa73be70SMatt Evans 	.vendor_id		= cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
38aa73be70SMatt Evans 	.device_id		= cpu_to_le16(PCI_DEVICE_ID_VESA),
39b025083dSJohn Floren 	.header_type		= PCI_HEADER_TYPE_NORMAL,
40b025083dSJohn Floren 	.revision_id		= 0,
41aa73be70SMatt Evans 	.class[2]		= 0x03,
42aa73be70SMatt Evans 	.subsys_vendor_id	= cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
43aa73be70SMatt Evans 	.subsys_id		= cpu_to_le16(PCI_SUBSYSTEM_ID_VESA),
44aa73be70SMatt Evans 	.bar[1]			= cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY),
454f045c57SSasha Levin 	.bar_size[1]		= VESA_MEM_SIZE,
46b025083dSJohn Floren };
47b025083dSJohn Floren 
4821ff329dSWill Deacon static struct device_header vesa_device = {
4921ff329dSWill Deacon 	.bus_type	= DEVICE_BUS_PCI,
5021ff329dSWill Deacon 	.data		= &vesa_pci_device,
5121ff329dSWill Deacon };
5221ff329dSWill Deacon 
53aba1efa5SPekka Enberg static struct framebuffer vesafb;
54aba1efa5SPekka Enberg 
55aba1efa5SPekka Enberg struct framebuffer *vesa__init(struct kvm *kvm)
56b025083dSJohn Floren {
57947392bcSSasha Levin 	u16 vesa_base_addr;
58aba1efa5SPekka Enberg 	char *mem;
5948d9e01aSSasha Levin 	int r;
60b025083dSJohn Floren 
61ce2fc8f5SAlexandru Elisei 	BUILD_BUG_ON(!is_power_of_two(VESA_MEM_SIZE));
62ce2fc8f5SAlexandru Elisei 	BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT);
63ce2fc8f5SAlexandru Elisei 
647bcceb95SPekka Enberg 	if (!kvm->cfg.vnc && !kvm->cfg.sdl && !kvm->cfg.gtk)
6507d52d77SSasha Levin 		return NULL;
66*5d6dd281SAlexandru Elisei 	vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE);
67*5d6dd281SAlexandru Elisei 	r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL);
687af40b91SSasha Levin 	if (r < 0)
69*5d6dd281SAlexandru Elisei 		goto out_error;
707af40b91SSasha Levin 
71aa73be70SMatt Evans 	vesa_pci_device.bar[0]		= cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
728f160708SAlexandru Elisei 	r = device__register(&vesa_device);
738f160708SAlexandru Elisei 	if (r < 0)
74*5d6dd281SAlexandru Elisei 		goto unregister_ioport;
75de960f08SPekka Enberg 
7696feb589SPekka Enberg 	mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
77*5d6dd281SAlexandru Elisei 	if (mem == MAP_FAILED) {
78*5d6dd281SAlexandru Elisei 		r = -errno;
79*5d6dd281SAlexandru Elisei 		goto unregister_device;
80*5d6dd281SAlexandru Elisei 	}
81aba1efa5SPekka Enberg 
82*5d6dd281SAlexandru Elisei 	r = kvm__register_dev_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
83*5d6dd281SAlexandru Elisei 	if (r < 0)
84*5d6dd281SAlexandru Elisei 		goto unmap_dev;
8596feb589SPekka Enberg 
86aba1efa5SPekka Enberg 	vesafb = (struct framebuffer) {
87aba1efa5SPekka Enberg 		.width			= VESA_WIDTH,
88aba1efa5SPekka Enberg 		.height			= VESA_HEIGHT,
89aba1efa5SPekka Enberg 		.depth			= VESA_BPP,
90aba1efa5SPekka Enberg 		.mem			= mem,
91aba1efa5SPekka Enberg 		.mem_addr		= VESA_MEM_ADDR,
927fca1897SSasha Levin 		.mem_size		= VESA_MEM_SIZE,
93df4239fbSSasha Levin 		.kvm			= kvm,
94aba1efa5SPekka Enberg 	};
95aba1efa5SPekka Enberg 	return fb__register(&vesafb);
96*5d6dd281SAlexandru Elisei 
97*5d6dd281SAlexandru Elisei unmap_dev:
98*5d6dd281SAlexandru Elisei 	munmap(mem, VESA_MEM_SIZE);
99*5d6dd281SAlexandru Elisei unregister_device:
100*5d6dd281SAlexandru Elisei 	device__unregister(&vesa_device);
101*5d6dd281SAlexandru Elisei unregister_ioport:
102*5d6dd281SAlexandru Elisei 	ioport__unregister(kvm, vesa_base_addr);
103*5d6dd281SAlexandru Elisei out_error:
104*5d6dd281SAlexandru Elisei 	return ERR_PTR(r);
105b025083dSJohn Floren }
106