This patch makes use of 'struct framebuffer' and moves the VNC code to ui/vnc.c in preparation for other framebuffer output targets.
Cc: Cyrill Gorcunov <gorcu...@gmail.com> Cc: Ingo Molnar <mi...@elte.hu> Cc: John Floren <j...@jfloren.net> Cc: Sasha Levin <levinsasha...@gmail.com> Signed-off-by: Pekka Enberg <penb...@kernel.org> --- tools/kvm/Makefile | 3 +- tools/kvm/hw/vesa.c | 72 ++++++++++++----------------------------- tools/kvm/include/kvm/i8042.h | 2 + tools/kvm/include/kvm/vesa.h | 8 +---- tools/kvm/include/kvm/vnc.h | 14 ++++++++ tools/kvm/kvm-run.c | 14 +++++++- tools/kvm/ui/vnc.c | 68 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 tools/kvm/include/kvm/vnc.h create mode 100644 tools/kvm/ui/vnc.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index 3f06dab..17c795b 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -51,6 +51,7 @@ OBJS += util/parse-options.o OBJS += util/rbtree-interval.o OBJS += util/strbuf.o OBJS += virtio/9p.o +OBJS += hw/vesa.o FLAGS_BFD=$(CFLAGS) -lbfd @@ -64,8 +65,8 @@ endif FLAGS_VNCSERVER=$(CFLAGS) -lvncserver has_vncserver := $(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER)) ifeq ($(has_vncserver),y) + OBJS += ui/vnc.o CFLAGS += -DCONFIG_HAS_VNCSERVER - OBJS += hw/vesa.o OBJS += hw/i8042.o LIBS += -lvncserver endif diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c index b99f2de..ad12d08 100644 --- a/tools/kvm/hw/vesa.c +++ b/tools/kvm/hw/vesa.c @@ -1,32 +1,19 @@ #include "kvm/vesa.h" #include "kvm/virtio-pci-dev.h" +#include "kvm/framebuffer.h" #include "kvm/kvm-cpu.h" #include "kvm/ioport.h" #include "kvm/util.h" #include "kvm/irq.h" #include "kvm/kvm.h" #include "kvm/pci.h" -#include "kvm/i8042.h" #include <sys/types.h> #include <sys/ioctl.h> #include <inttypes.h> #include <unistd.h> -#include <rfb/rfb.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 - -static char videomem[VESA_MEM_SIZE]; - static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) { return true; @@ -53,23 +40,24 @@ static struct pci_device_header vesa_pci_device = { .bar[1] = VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY, }; - -void vesa_mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write) +static void vesa_mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write) { if (!is_write) return; - memcpy(&videomem[addr - VESA_MEM_ADDR], data, len); + fb__write(addr, data, len); } -void vesa__init(struct kvm *kvm) +static struct framebuffer vesafb; + +struct framebuffer *vesa__init(struct kvm *kvm) { - u8 dev, line, pin; - pthread_t thread; u16 vesa_base_addr; + u8 dev, line, pin; + char *mem; if (irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line) < 0) - return; + return NULL; vesa_pci_device.irq_pin = pin; vesa_pci_device.irq_line = line; @@ -79,34 +67,16 @@ void vesa__init(struct kvm *kvm) 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. - */ - char argv[1][1] = {{0}}; - int argc = 1; - - rfbScreenInfoPtr server; - - server = rfbGetScreen(&argc, (char **) argv, VESA_WIDTH, VESA_HEIGHT, 8, 3, 4); - server->frameBuffer = videomem; - server->alwaysShared = TRUE; - server->kbdAddEvent = kbd_handle_key; - server->ptrAddEvent = kbd_handle_ptr; - rfbInitServer(server); - - while (rfbIsActive(server)) { - rfbMarkRectAsModified(server, 0, 0, VESA_WIDTH, VESA_HEIGHT); - rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME); - } - return NULL; + mem = calloc(1, VESA_MEM_SIZE); + if (!mem) + return NULL; + + vesafb = (struct framebuffer) { + .width = VESA_WIDTH, + .height = VESA_HEIGHT, + .depth = VESA_BPP, + .mem = mem, + .mem_addr = VESA_MEM_ADDR, + }; + return fb__register(&vesafb); } diff --git a/tools/kvm/include/kvm/i8042.h b/tools/kvm/include/kvm/i8042.h index 3416b64..066a8cc 100644 --- a/tools/kvm/include/kvm/i8042.h +++ b/tools/kvm/include/kvm/i8042.h @@ -1,6 +1,8 @@ #ifndef KVM__PCKBD_H #define KVM__PCKBD_H +struct kvm; + void kbd__init(struct kvm *kvm); #ifdef CONFIG_HAS_VNCSERVER diff --git a/tools/kvm/include/kvm/vesa.h b/tools/kvm/include/kvm/vesa.h index e9522a5..6621f68 100644 --- a/tools/kvm/include/kvm/vesa.h +++ b/tools/kvm/include/kvm/vesa.h @@ -13,13 +13,7 @@ struct kvm; struct int10_args; -void vesa_mmio_callback(u64, u8*, u32, u8); -void vesa__init(struct kvm *self); -void *vesa__dovnc(void *); +struct framebuffer *vesa__init(struct kvm *self); void int10_handler(struct int10_args *args); -#ifndef CONFIG_HAS_VNCSERVER -void vesa__init(struct kvm *self) { } -#endif - #endif diff --git a/tools/kvm/include/kvm/vnc.h b/tools/kvm/include/kvm/vnc.h new file mode 100644 index 0000000..da2f635 --- /dev/null +++ b/tools/kvm/include/kvm/vnc.h @@ -0,0 +1,14 @@ +#ifndef KVM__VNC_H +#define KVM__VNC_H + +struct framebuffer; + +#ifdef CONFIG_HAS_VNCSERVER +void vnc__init(struct framebuffer *fb); +#else +static inline void vnc__init(struct framebuffer *fb) +{ +} +#endif + +#endif /* KVM__VNC_H */ diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index 034a3ba..e6e180b 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -31,6 +31,8 @@ #include <kvm/vesa.h> #include <kvm/ioeventfd.h> #include <kvm/i8042.h> +#include <kvm/vnc.h> +#include <kvm/framebuffer.h> /* header files for gitish interface */ #include <kvm/kvm-run.h> @@ -426,13 +428,14 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) { struct virtio_net_parameters net_params; static char real_cmdline[2048]; + struct framebuffer *fb = NULL; unsigned int nr_online_cpus; int exit_code = 0; + u16 vidmode = 0; int max_cpus; char *hi; int i; void *ret; - u16 vidmode = 0; signal(SIGALRM, handle_sigalrm); signal(SIGQUIT, handle_sigquit); @@ -629,9 +632,14 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) if (vnc) { kbd__init(kvm); - vesa__init(kvm); + fb = vesa__init(kvm); } + if (fb) + vnc__init(fb); + + fb__start(); + thread_pool__init(nr_online_cpus); ioeventfd__start(); @@ -653,6 +661,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) exit_code = 1; } + fb__stop(); + virtio_blk__delete_all(kvm); virtio_rng__delete_all(kvm); diff --git a/tools/kvm/ui/vnc.c b/tools/kvm/ui/vnc.c new file mode 100644 index 0000000..086cf82 --- /dev/null +++ b/tools/kvm/ui/vnc.c @@ -0,0 +1,68 @@ +#include "kvm/vnc.h" + +#include "kvm/framebuffer.h" +#include "kvm/i8042.h" + +#include <linux/types.h> +#include <rfb/rfb.h> +#include <pthread.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 + +static void vnc__write(struct framebuffer *fb, u64 addr, u8 *data, u32 len) +{ + memcpy(&fb->mem[addr - fb->mem_addr], data, len); +} + +static void *vnc__thread(void *p) +{ + struct framebuffer *fb = p; + /* + * Make a fake argc and argv because the getscreen function + * seems to want it. + */ + char argv[1][1] = {{0}}; + int argc = 1; + + rfbScreenInfoPtr server; + + server = rfbGetScreen(&argc, (char **) argv, fb->width, fb->height, 8, 3, 4); + server->frameBuffer = fb->mem; + server->alwaysShared = TRUE; + server->kbdAddEvent = kbd_handle_key; + server->ptrAddEvent = kbd_handle_ptr; + rfbInitServer(server); + + while (rfbIsActive(server)) { + rfbMarkRectAsModified(server, 0, 0, fb->width, fb->height); + rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME); + } + return NULL; +} + +static int vnc__start(struct framebuffer *fb) +{ + pthread_t thread; + + if (pthread_create(&thread, NULL, vnc__thread, fb) != 0) + return -1; + + return 0; +} + +static struct fb_target_operations vnc_ops = { + .start = vnc__start, + .write = vnc__write, +}; + +void vnc__init(struct framebuffer *fb) +{ + fb__attach(fb, &vnc_ops); +} -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html