Add a simple VESA device which simply moves a framebuffer from guest kernel to a VNC server. VESA device PCI code is very similar to virtio-* PCI code. Signed-off-by: John Floren <john@xxxxxxxxxxx> [ turning code into patches and cleanup ] Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> --- tools/kvm/hw/vesa.c | 108 ++++++++++++++++++++++++++++++++ tools/kvm/include/kvm/ioport.h | 2 + tools/kvm/include/kvm/vesa.h | 27 ++++++++ tools/kvm/include/kvm/virtio-pci-dev.h | 3 + 4 files changed, 140 insertions(+), 0 deletions(-) create mode 100644 tools/kvm/hw/vesa.c create mode 100644 tools/kvm/include/kvm/vesa.h diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c new file mode 100644 index 0000000..3003aa5 --- /dev/null +++ b/tools/kvm/hw/vesa.c @@ -0,0 +1,108 @@ +#include "kvm/vesa.h" +#include "kvm/ioport.h" +#include "kvm/util.h" +#include "kvm/kvm.h" +#include "kvm/pci.h" +#include "kvm/kvm-cpu.h" +#include "kvm/irq.h" +#include "kvm/virtio-pci-dev.h" + +#include <rfb/rfb.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <inttypes.h> +#include <unistd.h> + +#define VESA_QUEUE_SIZE 128 +#define VESA_IRQ 14 + +/* + * This "6000" value is pretty much the result of experimentation + * It seems that around this value, things update pretty smoothly + */ +#define VESA_UPDATE_TIME 6000 + +u8 videomem[VESA_MEM_SIZE]; + +static bool vesa_pci_io_in(struct kvm *kvm, u16 port, void *data, int size, u32 count) +{ + printf("vesa in port=%u\n", port); + return true; +} + +static bool vesa_pci_io_out(struct kvm *kvm, u16 port, void *data, int size, u32 count) +{ + printf("vesa out port=%u\n", port); + return true; +} + +static struct ioport_operations vesa_io_ops = { + .io_in = vesa_pci_io_in, + .io_out = vesa_pci_io_out, +}; + +static struct pci_device_header vesa_pci_device = { + .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, + .device_id = PCI_DEVICE_ID_VESA, + .header_type = PCI_HEADER_TYPE_NORMAL, + .revision_id = 0, + .class = 0x030000, + .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, + .subsys_id = PCI_SUBSYSTEM_ID_VESA, + .bar[0] = IOPORT_VESA | PCI_BASE_ADDRESS_SPACE_IO, + .bar[1] = VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY, +}; + + +void vesa_mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write) +{ + if (is_write) + memcpy(&videomem[addr - VESA_MEM_ADDR], data, len); + + return; +} + +void vesa__init(struct kvm *kvm) +{ + u8 dev, line, pin; + pthread_t thread; + + if (irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line) < 0) + return; + + vesa_pci_device.irq_pin = pin; + vesa_pci_device.irq_line = line; + pci__register(&vesa_pci_device, dev); + ioport__register(IOPORT_VESA, &vesa_io_ops, IOPORT_VESA_SIZE); + + kvm__register_mmio(VESA_MEM_ADDR, VESA_MEM_SIZE, &vesa_mmio_callback); + pthread_create(&thread, NULL, vesa__dovnc, kvm); +} + +/* + * This starts a VNC server to display the framebuffer. + * It's not altogether clear this belongs here rather than in kvm-run.c + */ +void *vesa__dovnc(void *v) +{ + /* + * Make a fake argc and argv because the getscreen function + * seems to want it. + */ + int ac = 1; + char av[1][1] = {{0} }; + rfbScreenInfoPtr server; + + server = rfbGetScreen(&ac, (char **)av, VESA_WIDTH, VESA_HEIGHT, 8, 3, 4); + server->frameBuffer = (char *)videomem; + server->alwaysShared = TRUE; + rfbInitServer(server); + + while (rfbIsActive(server)) { + rfbMarkRectAsModified(server, 0, 0, VESA_WIDTH, VESA_HEIGHT); + rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME); + } + return NULL; +} + diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h index 218530c..8253938 100644 --- a/tools/kvm/include/kvm/ioport.h +++ b/tools/kvm/include/kvm/ioport.h @@ -7,6 +7,8 @@ /* some ports we reserve for own use */ #define IOPORT_DBG 0xe0 +#define IOPORT_VESA 0xa200 +#define IOPORT_VESA_SIZE 256 #define IOPORT_VIRTIO_P9 0xb200 /* Virtio 9P device */ #define IOPORT_VIRTIO_P9_SIZE 256 #define IOPORT_VIRTIO_BLK 0xc200 /* Virtio block device */ diff --git a/tools/kvm/include/kvm/vesa.h b/tools/kvm/include/kvm/vesa.h new file mode 100644 index 0000000..3e58587 --- /dev/null +++ b/tools/kvm/include/kvm/vesa.h @@ -0,0 +1,27 @@ +#ifndef KVM__VESA_H +#define KVM__VESA_H + +#include <linux/types.h> + +#define VESA_WIDTH 640 +#define VESA_HEIGHT 480 + +#define VESA_MEM_ADDR 0xd0000000 +#define VESA_MEM_SIZE (4*VESA_WIDTH*VESA_HEIGHT) +#define VESA_BPP 32 + +struct kvm; +struct int10args; + +void vesa_mmio_callback(u64, u8*, u32, u8); +void vesa__init(struct kvm *self); +void *vesa__dovnc(void *); +void int10handler(struct int10args *args); + +#ifndef CONFIG_HAS_VNCSERVER +void vesa__init(struct kvm *self) { } +#endif + +extern u8 videomem[VESA_MEM_SIZE]; + +#endif diff --git a/tools/kvm/include/kvm/virtio-pci-dev.h b/tools/kvm/include/kvm/virtio-pci-dev.h index 1b7862e..ca373df 100644 --- a/tools/kvm/include/kvm/virtio-pci-dev.h +++ b/tools/kvm/include/kvm/virtio-pci-dev.h @@ -13,8 +13,11 @@ #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 #define PCI_DEVICE_ID_VIRTIO_RNG 0x1004 #define PCI_DEVICE_ID_VIRTIO_P9 0x1009 +#define PCI_DEVICE_ID_VESA 0x2000 #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 +#define PCI_SUBSYSTEM_ID_VESA 0x0004 + #endif /* VIRTIO_PCI_DEV_H_ */ -- 1.7.5.rc3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html