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