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 21b025083dSJohn Floren static struct pci_device_header vesa_pci_device = { 22aa73be70SMatt Evans .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), 23aa73be70SMatt Evans .device_id = cpu_to_le16(PCI_DEVICE_ID_VESA), 24b025083dSJohn Floren .header_type = PCI_HEADER_TYPE_NORMAL, 25b025083dSJohn Floren .revision_id = 0, 26aa73be70SMatt Evans .class[2] = 0x03, 27aa73be70SMatt Evans .subsys_vendor_id = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET), 28aa73be70SMatt Evans .subsys_id = cpu_to_le16(PCI_SUBSYSTEM_ID_VESA), 29aa73be70SMatt Evans .bar[1] = cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY), 304f045c57SSasha Levin .bar_size[1] = VESA_MEM_SIZE, 31b025083dSJohn Floren }; 32b025083dSJohn Floren 3321ff329dSWill Deacon static struct device_header vesa_device = { 3421ff329dSWill Deacon .bus_type = DEVICE_BUS_PCI, 3521ff329dSWill Deacon .data = &vesa_pci_device, 3621ff329dSWill Deacon }; 3721ff329dSWill Deacon 38*5a8e4f25SAlexandru Elisei static struct framebuffer vesafb = { 39*5a8e4f25SAlexandru Elisei .width = VESA_WIDTH, 40*5a8e4f25SAlexandru Elisei .height = VESA_HEIGHT, 41*5a8e4f25SAlexandru Elisei .depth = VESA_BPP, 42*5a8e4f25SAlexandru Elisei .mem_addr = VESA_MEM_ADDR, 43*5a8e4f25SAlexandru Elisei .mem_size = VESA_MEM_SIZE, 44*5a8e4f25SAlexandru Elisei }; 45*5a8e4f25SAlexandru Elisei 46*5a8e4f25SAlexandru Elisei static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 47*5a8e4f25SAlexandru Elisei { 48*5a8e4f25SAlexandru Elisei return true; 49*5a8e4f25SAlexandru Elisei } 50*5a8e4f25SAlexandru Elisei 51*5a8e4f25SAlexandru Elisei static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size) 52*5a8e4f25SAlexandru Elisei { 53*5a8e4f25SAlexandru Elisei return true; 54*5a8e4f25SAlexandru Elisei } 55*5a8e4f25SAlexandru Elisei 56*5a8e4f25SAlexandru Elisei static struct ioport_operations vesa_io_ops = { 57*5a8e4f25SAlexandru Elisei .io_in = vesa_pci_io_in, 58*5a8e4f25SAlexandru Elisei .io_out = vesa_pci_io_out, 59*5a8e4f25SAlexandru Elisei }; 60*5a8e4f25SAlexandru Elisei 61*5a8e4f25SAlexandru Elisei static int vesa__bar_activate(struct kvm *kvm, struct pci_device_header *pci_hdr, 62*5a8e4f25SAlexandru Elisei int bar_num, void *data) 63*5a8e4f25SAlexandru Elisei { 64*5a8e4f25SAlexandru Elisei /* We don't support remapping of the framebuffer. */ 65*5a8e4f25SAlexandru Elisei return 0; 66*5a8e4f25SAlexandru Elisei } 67*5a8e4f25SAlexandru Elisei 68*5a8e4f25SAlexandru Elisei static int vesa__bar_deactivate(struct kvm *kvm, struct pci_device_header *pci_hdr, 69*5a8e4f25SAlexandru Elisei int bar_num, void *data) 70*5a8e4f25SAlexandru Elisei { 71*5a8e4f25SAlexandru Elisei /* We don't support remapping of the framebuffer. */ 72*5a8e4f25SAlexandru Elisei return -EINVAL; 73*5a8e4f25SAlexandru Elisei } 74aba1efa5SPekka Enberg 75aba1efa5SPekka Enberg struct framebuffer *vesa__init(struct kvm *kvm) 76b025083dSJohn Floren { 77947392bcSSasha Levin u16 vesa_base_addr; 78aba1efa5SPekka Enberg char *mem; 7948d9e01aSSasha Levin int r; 80b025083dSJohn Floren 81ce2fc8f5SAlexandru Elisei BUILD_BUG_ON(!is_power_of_two(VESA_MEM_SIZE)); 82ce2fc8f5SAlexandru Elisei BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT); 83ce2fc8f5SAlexandru Elisei 845d6dd281SAlexandru Elisei vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE); 855d6dd281SAlexandru Elisei r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL); 867af40b91SSasha Levin if (r < 0) 875d6dd281SAlexandru Elisei goto out_error; 887af40b91SSasha Levin 89aa73be70SMatt Evans vesa_pci_device.bar[0] = cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO); 90c5e3c9eeSAlexandru Elisei vesa_pci_device.bar_size[0] = PCI_IO_SIZE; 91*5a8e4f25SAlexandru Elisei r = pci__register_bar_regions(kvm, &vesa_pci_device, vesa__bar_activate, 92*5a8e4f25SAlexandru Elisei vesa__bar_deactivate, NULL); 93*5a8e4f25SAlexandru Elisei if (r < 0) 94*5a8e4f25SAlexandru Elisei goto unregister_ioport; 95*5a8e4f25SAlexandru Elisei 968f160708SAlexandru Elisei r = device__register(&vesa_device); 978f160708SAlexandru Elisei if (r < 0) 985d6dd281SAlexandru Elisei goto unregister_ioport; 99de960f08SPekka Enberg 10096feb589SPekka Enberg mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0); 1015d6dd281SAlexandru Elisei if (mem == MAP_FAILED) { 1025d6dd281SAlexandru Elisei r = -errno; 1035d6dd281SAlexandru Elisei goto unregister_device; 1045d6dd281SAlexandru Elisei } 105aba1efa5SPekka Enberg 1065d6dd281SAlexandru Elisei r = kvm__register_dev_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem); 1075d6dd281SAlexandru Elisei if (r < 0) 1085d6dd281SAlexandru Elisei goto unmap_dev; 10996feb589SPekka Enberg 110*5a8e4f25SAlexandru Elisei vesafb.mem = mem; 111*5a8e4f25SAlexandru Elisei vesafb.kvm = kvm; 112aba1efa5SPekka Enberg return fb__register(&vesafb); 1135d6dd281SAlexandru Elisei 1145d6dd281SAlexandru Elisei unmap_dev: 1155d6dd281SAlexandru Elisei munmap(mem, VESA_MEM_SIZE); 1165d6dd281SAlexandru Elisei unregister_device: 1175d6dd281SAlexandru Elisei device__unregister(&vesa_device); 1185d6dd281SAlexandru Elisei unregister_ioport: 1195d6dd281SAlexandru Elisei ioport__unregister(kvm, vesa_base_addr); 1205d6dd281SAlexandru Elisei out_error: 1215d6dd281SAlexandru Elisei return ERR_PTR(r); 122b025083dSJohn Floren } 123