All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Paravirt framebuffer kernel infrastructure [1/6]
@ 2006-08-18 21:05 Jeremy Katz
  2006-08-21 14:20 ` Markus Armbruster
  2006-08-29 14:39 ` Laurent Vivier
  0 siblings, 2 replies; 3+ messages in thread
From: Jeremy Katz @ 2006-08-18 21:05 UTC (permalink / raw)
  To: xen-devel
  Cc: Ian Pratt, Anthony Liguori, Markus Armbruster, Christian Limpach

[-- Attachment #1: Type: text/plain, Size: 367 bytes --]

Basic kernel space support for virtual framebuffer and keyboard.  This
is the work Markus did to port Anthony's original code to use xenstore
and for current kernels.  It should include all of the fixes from the
last submission

Signed-off-by: Jeremy Katz <katzj@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>

Jeremy

[-- Attachment #2: xen-pvfb-1.patch --]
[-- Type: text/x-patch, Size: 27151 bytes --]

diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c
--- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Tue Aug 15 19:53:55 2006 +0100
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Fri Aug 18 16:17:58 2006 -0400
@@ -1871,8 +1871,12 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 	} else {
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+		conswitchp = &dummy_con;
+#else
 		extern int console_use_vt;
 		console_use_vt = 0;
+#endif
 	}
 }
 
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Aug 15 19:53:55 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Fri Aug 18 16:17:58 2006 -0400
@@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND
 	  dedicated device-driver domain, or your master control domain
 	  (domain 0), then you almost certainly want to say Y here.
 
+config XEN_FRAMEBUFFER
+	tristate "Framebuffer-device frontend driver"
+	depends on XEN && FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	default y
+	help
+	  The framebuffer-device frontend drivers allows the kernel to create a
+	  virtual framebuffer.  This framebuffer can be viewed in another
+	  domain.  Unless this domain has access to a real video card, you
+	  probably want to say Y here.
+
+config XEN_KEYBOARD
+	tristate "Keyboard-device frontend driver"
+	depends on XEN
+	default y
+	help
+	  The keyboard-device frontend driver allows the kernel to create a
+	  virtual keyboard.  This keyboard can then be driven by another
+	  domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
+	  want to say Y here.
+
 config XEN_SCRUB_PAGES
 	bool "Scrub memory before freeing it to Xen"
 	default y
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Aug 15 19:53:55 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Aug 18 16:17:58 2006 -0400
@@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= net
 obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
 obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
+obj-$(CONFIG_XEN_FRAMEBUFFER)		+= xenfb/
+obj-$(CONFIG_XEN_KEYBOARD)		+= xenkbd/
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/mm/memory.c
--- a/linux-2.6-xen-sparse/mm/memory.c	Tue Aug 15 19:53:55 2006 +0100
+++ b/linux-2.6-xen-sparse/mm/memory.c	Fri Aug 18 16:17:58 2006 -0400
@@ -881,6 +881,7 @@ unsigned long zap_page_range(struct vm_a
 		tlb_finish_mmu(tlb, address, end);
 	return end;
 }
+EXPORT_SYMBOL(zap_page_range);
 
 /*
  * Do a quick page-table lookup for a single page.
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/xenfb/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenfb/Makefile	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_FRAMEBUFFER)	:= xenfb.o
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/xenfb/xenfb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenfb/xenfb.c	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,568 @@
+/*
+ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
+ *
+ * Copyright (C) 2005-2006
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  Based on linux/drivers/video/q40fb.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <asm/hypervisor.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <linux/xenfb.h>
+#include <linux/kthread.h>
+
+static int xenfb_fps = 20;
+static unsigned long xenfb_mem_len = 2 * 1024 * 1024;
+
+struct xenfb_mapping
+{
+	struct list_head	next;
+	struct vm_area_struct	*vma;
+	atomic_t		map_refs;
+	int			faults;
+	struct xenfb_info	*info;
+};
+
+struct xenfb_info
+{
+	struct task_struct		*kthread;
+	wait_queue_head_t		wq;
+
+	unsigned char			*fb;
+	struct fb_fix_screeninfo	*fix;
+	struct fb_var_screeninfo	*var;
+	struct fb_info			*fb_info;
+	struct timer_list		refresh;
+	int				dirty;
+	int				y1, y2;
+	int				x1, x2;
+
+	struct semaphore		mm_lock;
+	int				nr_pages;
+	struct page			**pages;
+	struct list_head		mappings;
+
+	unsigned			evtchn;
+	struct xenfb_page		*page;
+	unsigned long 			*mfns;
+};
+
+static void xenfb_do_update(struct xenfb_info *info,
+			    int x, int y, int w, int h)
+{
+	union xenfb_out_event event;
+	__u32 prod;
+
+	event.type = XENFB_TYPE_UPDATE;
+	event.update.x = x;
+	event.update.y = y;
+	event.update.width = w;
+	event.update.height = h;
+
+	prod = info->page->out_prod;
+	if (prod - info->page->out_cons == XENFB_RING_SIZE(info->page->out))
+		return;		/* ring buffer full, event lost */
+	XENFB_RING_REF(info->page->out, prod) = event;
+	info->page->out_prod = prod + 1;
+
+	notify_remote_via_evtchn(info->evtchn);
+}
+
+static int xenfb_queue_full(struct xenfb_info *info)
+{
+	__u32 cons, prod;
+
+	prod = info->page->out_prod;
+	cons = info->page->out_cons;
+	return prod - cons == XENFB_RING_SIZE(info->page->out);
+}
+
+static void xenfb_update_screen(struct xenfb_info *info)
+{
+	int y1, y2, x1, x2;
+	struct list_head *item;
+	struct xenfb_mapping *map;
+
+	if (xenfb_queue_full(info))
+		return;
+
+	y1 = info->y1;
+	y2 = info->y2;
+	x1 = info->x1;
+	x2 = info->x2;
+	info->dirty = info->y1 = info->y2 = info->x1 = info->x2 = 0;
+	down(&info->mm_lock);
+	list_for_each(item, &info->mappings) {
+		map = list_entry(item, struct xenfb_mapping, next);
+		if (!map->faults)
+			continue;
+		zap_page_range(map->vma, map->vma->vm_start,
+			       map->vma->vm_end - map->vma->vm_start, NULL);
+		map->faults = 0;
+	}
+	up(&info->mm_lock);
+
+	xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
+}
+
+static int xenfb_thread(void *data)
+{
+	struct xenfb_info *info = data;
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&info->wq, &wait);
+	for (;;) {
+		if (kthread_should_stop())
+			break;
+		if (info->dirty)
+			xenfb_update_screen(info);
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	}
+	remove_wait_queue(&info->wq, &wait);
+	return 0;
+}
+
+static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	u32 v;
+
+	if (regno > info->cmap.len)
+		return 1;
+
+	red   >>= (16 - info->var.red.length);
+	green >>= (16 - info->var.green.length);
+	blue  >>= (16 - info->var.blue.length);
+
+	v = (red << info->var.red.offset) |
+	    (green << info->var.green.offset) |
+	    (blue << info->var.blue.offset);
+
+	switch (info->var.bits_per_pixel) {
+	case 16:
+	case 24:
+	case 32:
+		((u32 *)info->pseudo_palette)[regno] = v;
+		break;
+	}
+	
+	return 0;
+}
+
+static void xenfb_timer(unsigned long data)
+{
+	struct xenfb_info *info = (struct xenfb_info *)data;
+	info->dirty++;
+	wake_up(&info->wq);
+}
+
+static void xenfb_refresh(struct xenfb_info *info,
+			  int x1, int y1, int w, int h)
+{
+	int y2, x2;
+
+	y2 = y1 + h;
+	x2 = x1 + w;
+	if (info->y2 == 0) {
+		info->y1 = y1;
+		info->y2 = y2;
+	}
+	if (info->x2 == 0) {
+		info->x1 = x1;
+		info->x2 = x2;
+	}
+
+	if (info->y1 > y1)
+		info->y1 = y1;
+	if (info->y2 < y2)
+		info->y2 = y2;
+	if (info->x1 > x1)
+		info->x1 = x1;
+	if (info->x2 < x2)
+		info->x2 = x2;
+
+	if (timer_pending(&info->refresh))
+		return;
+
+	mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
+}
+
+static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+	struct xenfb_info *info = p->par;
+
+	cfb_fillrect(p, rect);
+	xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
+}
+
+static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+	struct xenfb_info *info = p->par;
+
+	cfb_imageblit(p, image);
+	xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
+}
+
+static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+	struct xenfb_info *info = p->par;
+
+	cfb_copyarea(p, area);
+	xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
+}
+
+static void xenfb_vm_open(struct vm_area_struct *vma)
+{
+	struct xenfb_mapping *map = vma->vm_private_data;
+	atomic_inc(&map->map_refs);
+}
+
+static void xenfb_vm_close(struct vm_area_struct *vma)
+{
+	struct xenfb_mapping *map = vma->vm_private_data;
+	struct xenfb_info *info = map->info;
+
+	down(&info->mm_lock);
+	if (atomic_dec_and_test(&map->map_refs)) {
+		list_del(&map->next);
+		kfree(map);
+	}
+	up(&info->mm_lock);
+}
+
+static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
+				    unsigned long vaddr, int *type)
+{
+	struct xenfb_mapping *map = vma->vm_private_data;
+	struct xenfb_info *info = map->info;
+	int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
+	struct page *page;
+	int y1, y2;
+
+	if (pgnr >= info->nr_pages)
+		return NOPAGE_SIGBUS;
+
+	down(&info->mm_lock);
+	page = info->pages[pgnr];
+	get_page(page);
+	map->faults++;
+
+	y1 = pgnr * PAGE_SIZE / info->fix->line_length;
+	y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length;
+	if (y2 > info->var->yres)
+		y2 = info->var->yres;
+	xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1);
+	up(&info->mm_lock);
+
+	if (type)
+		*type = VM_FAULT_MINOR;
+
+	return page;
+}
+
+static struct vm_operations_struct xenfb_vm_ops = {
+	.open	= xenfb_vm_open,
+	.close	= xenfb_vm_close,
+	.nopage	= xenfb_vm_nopage,
+};
+
+static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
+{
+	struct xenfb_info *info = fb_info->par;
+	struct xenfb_mapping *map;
+	int ret;
+	int map_pages;
+
+	down(&info->mm_lock);
+
+	ret = -EINVAL;
+	if (!(vma->vm_flags & VM_WRITE))
+		goto out;
+	if (!(vma->vm_flags & VM_SHARED))
+		goto out;
+	if (vma->vm_pgoff != 0)
+		goto out;
+
+	map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
+	if (map_pages > info->nr_pages)
+		goto out;
+
+	ret = -ENOMEM;
+	map = kmalloc(sizeof(*map), GFP_KERNEL);
+	if (map == NULL)
+		goto out;
+	memset(map, 0, sizeof(*map));
+
+	map->vma = vma;
+	map->faults = 0;
+	map->info = info;
+	atomic_set(&map->map_refs, 1);
+	list_add(&map->next, &info->mappings);
+	vma->vm_ops = &xenfb_vm_ops;
+	vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
+	vma->vm_private_data = map;
+	ret = 0;
+
+ out:
+	up(&info->mm_lock);
+	return ret;
+}
+
+static struct fb_ops xenfb_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= xenfb_setcolreg,
+	.fb_fillrect	= xenfb_fillrect,
+	.fb_copyarea	= xenfb_copyarea,
+	.fb_imageblit	= xenfb_imageblit,
+	.fb_mmap	= xenfb_mmap,
+};
+
+static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
+				       struct pt_regs *regs)
+{
+	struct xenfb_info *info = dev_id;
+	__u32 cons, prod;
+
+	if (!info->page || !info->page->initialized)
+		return IRQ_NONE;
+
+	prod = info->page->in_prod;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = info->page->in_cons; cons != prod; cons++) {
+		union xenfb_in_event *event;
+		event = &XENFB_RING_REF(info->page->in, cons);
+		notify_remote_via_evtchn(info->evtchn);
+	}
+	/* FIXME do I need a wmb() here? */
+	info->page->in_cons = cons;
+
+	return IRQ_HANDLED;
+}
+
+static unsigned long vmalloc_to_mfn(void *address)
+{
+	return pfn_to_mfn(vmalloc_to_pfn(address));
+}
+
+static struct xenfb_info *xenfb_info;
+static int xenfb_irq;
+
+static int __init xenfb_probe(void)
+{
+	struct xenfb_info *info;
+	int i, ret;
+	struct fb_info *fb_info;
+	struct evtchn_alloc_unbound alloc_unbound;
+	struct xenbus_transaction xbt;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (info == NULL)
+		return -ENOMEM;
+	memset(info, 0, sizeof(*info));
+
+	INIT_LIST_HEAD(&info->mappings);
+
+	info->fb = vmalloc(xenfb_mem_len);
+	if (info->fb == NULL)
+		goto error;
+	memset(info->fb, 0, xenfb_mem_len);
+	info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	info->pages = kmalloc(sizeof(struct page*)*info->nr_pages, GFP_KERNEL);
+	if (info->pages == NULL)
+		goto error_vfree;
+	for (i = 0; i < info->nr_pages; i++)
+		info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
+
+	fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
+	if (fb_info == NULL)
+		goto error_kfree;
+
+	info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
+	/* set up shared page */
+	info->page = (void *)__get_free_page(GFP_KERNEL);
+	if (!info->page)
+		goto error_kfree;
+	/* set up event channel */
+	alloc_unbound.dom = DOMID_SELF;
+	alloc_unbound.remote_dom = 0;
+	ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+					  &alloc_unbound);
+	if (ret)
+		goto error_freep;
+	info->evtchn = alloc_unbound.port;
+
+	for (i = 0; i < info->nr_pages; i++)
+		info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+	info->page->pd[0] = vmalloc_to_mfn(info->mfns);
+	info->page->pd[1] = 0;
+	info->page->width = 800;
+	info->page->height = 600;
+	info->page->depth = 32;
+	info->page->line_length = (info->page->depth / 8) * info->page->width;
+	info->page->mem_length = xenfb_mem_len;
+	info->page->in_cons = info->page->in_prod = 0;
+	info->page->out_cons = info->page->out_prod = 0;
+
+	ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
+					0, "xenfb", info);
+	if (ret < 0)
+		// FIXME need to close evtchn?
+		goto error_kfree;
+
+	xenfb_irq = ret;
+	xenfb_info = info;
+
+	fb_info->pseudo_palette = fb_info->par;
+	fb_info->par = info;
+	fb_info->screen_base = info->fb;
+
+	memset(&fb_info->var, 0, sizeof(fb_info->var));
+	memset(&fb_info->fix, 0, sizeof(fb_info->fix));
+
+	fb_info->fbops = &xenfb_fb_ops;
+	fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
+	fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
+	fb_info->var.bits_per_pixel = info->page->depth;
+
+	fb_info->var.red = (struct fb_bitfield){16, 8, 0};
+	fb_info->var.green = (struct fb_bitfield){8, 8, 0};
+	fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
+
+	fb_info->var.activate = FB_ACTIVATE_NOW;
+	fb_info->var.height = -1;
+	fb_info->var.width = -1;
+	fb_info->var.vmode = FB_VMODE_NONINTERLACED;
+
+	fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
+	fb_info->fix.line_length = info->page->line_length;
+	fb_info->fix.smem_start = 0;
+	fb_info->fix.smem_len = xenfb_mem_len;
+	strcpy(fb_info->fix.id, "xen");
+	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
+	fb_info->fix.accel = FB_ACCEL_NONE;
+
+	fb_info->flags = FBINFO_FLAG_DEFAULT;
+
+	fb_alloc_cmap(&fb_info->cmap, 256, 0);
+
+	info->fb_info = fb_info;
+	info->fix = &fb_info->fix;
+	info->var = &fb_info->var;
+
+	init_MUTEX(&info->mm_lock);
+	init_waitqueue_head(&info->wq);
+	init_timer(&info->refresh);
+	info->refresh.function = xenfb_timer;
+	info->refresh.data = (unsigned long)info;
+
+	info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
+
+	ret = register_framebuffer(fb_info);
+	if (ret)
+		goto error_unbind;
+
+ again:
+	ret = xenbus_transaction_start(&xbt);
+	if (ret)
+		goto error_unreg;
+	ret = xenbus_printf(xbt, "vfb", "page-ref", "%lu",
+			    virt_to_mfn(info->page));
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, "vfb", "event-channel", "%u",
+			    info->evtchn);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_transaction_end(xbt, 0);
+	if (ret) {
+		if (ret == -EAGAIN)
+			goto again;
+		goto error_unreg;
+	}
+
+	info->page->initialized = 1; /* FIXME needed?  move up? */
+
+	return 0;
+
+ error_xenbus:
+	xenbus_transaction_end(xbt, 1);
+ error_unreg:
+	unregister_framebuffer(fb_info);
+ error_unbind:
+	unbind_from_irqhandler(xenfb_irq, info);
+	xenfb_irq = 0;
+ error_freep:
+	free_page((unsigned long)info->page);
+ error_kfree:
+	kfree(info->pages);
+ error_vfree:
+	vfree(info->fb);
+ error:
+	kfree(info);
+	xenfb_info = NULL;
+
+	return -ENODEV;
+}
+
+void xenfb_resume(void)
+{
+#if 0 /* FIXME */
+	int i, ret;
+
+	xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn);
+	for (i = 0; i < xenfb_info->nr_pages; i++)
+		xenfb_info->mfns[i] = vmalloc_to_mfn(xenfb_info->fb + i * PAGE_SIZE);
+	xenfb_info->page->pd[0] = vmalloc_to_mfn(xenfb_info->mfns);
+
+	if (xenfb_irq)
+		unbind_from_irqhandler(xenfb_irq, NULL);
+
+	printk("xenfb: resume(%d)\n", xen_start_info->fbdev_evtchn);
+	ret = bind_evtchn_to_irqhandler(xen_start_info->fbdev_evtchn,
+					xenfb_event_handler, 0, "xenfb", xenfb_info);
+	if (ret <= 0)
+		return;
+	xenfb_irq = ret;
+#else
+	printk(KERN_DEBUG "xenfb_resume not implemented\n");
+#endif
+}
+
+static int __init xenfb_init(void)
+{
+	return xenfb_probe();
+}
+
+static void __exit xenfb_cleanup(void)
+{
+	struct xenfb_info *info = xenfb_info;
+
+	unregister_framebuffer(info->fb_info);
+	unbind_from_irqhandler(xenfb_irq, info);
+	xenfb_irq = 0;
+	free_page((unsigned long)info->page);
+	kfree(info->pages);
+	vfree(info->fb);
+	kfree(info);
+	xenfb_info = NULL;
+}
+
+module_init(xenfb_init);
+module_exit(xenfb_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/xenkbd/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenkbd/Makefile	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,1 @@
+obj-$(CONFIG_XEN_KEYBOARD)	+= xenkbd.o
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/drivers/xen/xenkbd/xenkbd.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/xenkbd/xenkbd.c	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,205 @@
+/*
+ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  Based on linux/drivers/input/mouse/sermouse.c
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <asm/hypervisor.h>
+#include <xen/evtchn.h>
+#include <xen/xenbus.h>
+#include <linux/xenkbd.h>
+
+struct xenkbd_device
+{
+	struct input_dev *dev;
+	struct xenkbd_info *info;
+	unsigned evtchn;
+};
+
+static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
+{
+	struct xenkbd_device *dev = dev_id;
+	struct xenkbd_info *info = dev ? dev->info : 0;
+	static int button_map[3] = { BTN_RIGHT, BTN_MIDDLE, BTN_LEFT };
+	__u32 cons, prod;
+
+	if (!info || !info->initialized)
+		return IRQ_NONE;
+
+	prod = info->in_prod;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = info->in_cons; cons != prod; cons++) {
+		union xenkbd_in_event *event;
+		event = &XENKBD_RING_REF(info->in, cons);
+	
+		switch (event->type) {
+		case XENKBD_TYPE_MOTION:
+			input_report_rel(dev->dev, REL_X, event->motion.rel_x);
+			input_report_rel(dev->dev, REL_Y, event->motion.rel_y);
+			break;
+		case XENKBD_TYPE_BUTTON:
+			if (event->button.button < 3)
+				input_report_key(dev->dev,
+						 button_map[event->button.button],
+						 event->button.pressed);
+			break;
+		case XENKBD_TYPE_KEY:
+			input_report_key(dev->dev, event->key.keycode, event->key.pressed);
+			break;
+		}
+
+		notify_remote_via_evtchn(dev->evtchn);
+	}
+	input_sync(dev->dev);
+	/* FIXME do I need a wmb() here? */
+	info->in_cons = cons;
+
+	return IRQ_HANDLED;
+}
+
+static struct xenkbd_device *xenkbd_dev;
+static int xenkbd_irq;
+
+int __init xenkbd_init(void)
+{
+	int ret = 0;
+	int i;
+	struct xenkbd_device *dev;
+	struct input_dev *input_dev;
+	struct evtchn_alloc_unbound alloc_unbound;
+	struct xenbus_transaction xbt;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!dev || !input_dev)
+		return -ENOMEM;
+
+	dev->dev = input_dev;
+	dev->info = (void *)__get_free_page(GFP_KERNEL);
+	if (!dev->info) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	dev->info->initialized = 0;
+
+	alloc_unbound.dom = DOMID_SELF;
+	alloc_unbound.remote_dom = 0;
+	ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+					  &alloc_unbound);
+	if (ret)
+		goto error_freep;
+	dev->evtchn = alloc_unbound.port;
+	ret = bind_evtchn_to_irqhandler(dev->evtchn, input_handler, 0,
+					"xenkbd", dev);
+	if (ret < 0)
+		goto error_freep;
+
+	xenkbd_irq = ret;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+	/* FIXME not sure this is quite right */
+	for (i = 0; i < 256; i++)
+		set_bit(i, input_dev->keybit);
+
+	input_dev->name = "Xen Virtual Keyboard/Mouse";
+
+	input_register_device(input_dev);
+
+ again:
+	ret = xenbus_transaction_start(&xbt);
+	if (ret)
+		goto error_unreg;
+	ret = xenbus_printf(xbt, "vkbd", "page-ref", "%lu",
+			    virt_to_mfn(dev->info));
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_printf(xbt, "vkbd", "event-channel", "%u",
+			    dev->evtchn);
+	if (ret)
+		goto error_xenbus;
+	ret = xenbus_transaction_end(xbt, 0);
+	if (ret) {
+		if (ret == -EAGAIN)
+			goto again;
+		/* FIXME really retry forever? */
+		goto error_unreg;
+	}
+
+	dev->info->in_cons = dev->info->in_prod = 0;
+	dev->info->out_cons = dev->info->out_prod = 0;
+	dev->info->initialized = 1; /* FIXME needed?  move up? */
+
+	xenkbd_dev = dev;
+
+	return ret;
+
+	
+ error_xenbus:
+	xenbus_transaction_end(xbt, 1);
+ error_unreg:
+	input_unregister_device(input_dev);
+	unbind_from_irqhandler(xenkbd_irq, dev);
+	xenkbd_irq = 0;
+ error_freep:
+	free_page((unsigned long)dev->info);
+ error:
+	kfree(dev);
+	xenkbd_dev = NULL;
+	return ret;
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+	input_unregister_device(xenkbd_dev->dev);
+	unbind_from_irqhandler(xenkbd_irq, xenkbd_dev);
+	xenkbd_irq = 0;
+	free_page((unsigned long)xenkbd_dev->info);
+	kfree(xenkbd_dev);
+	xenkbd_dev = NULL;
+}
+
+void xenkbd_resume(void)
+{
+#if 0 /* FIXME */
+	int ret;
+
+	if (xenkbd_dev && xen_start_info->kbd_evtchn) {
+		if (xenkbd_irq)
+			unbind_from_irqhandler(xenkbd_irq, NULL);
+
+		ret = bind_evtchn_to_irqhandler(xen_start_info->kbd_evtchn,
+						input_handler,
+						0,
+						"xenkbd",
+						xenkbd_dev);
+
+		if (ret <= 0)
+			return;
+
+		xenkbd_irq = ret;
+		xenkbd_dev->info = mfn_to_virt(xen_start_info->kbd_mfn);
+	}
+#else
+	printk(KERN_DEBUG "xenkbd_resume not implemented\n");
+#endif
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_LICENSE("GPL");
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/include/linux/xenfb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/include/linux/xenfb.h	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,97 @@
+/*
+ * linux/include/linux/xenfb.h -- Xen virtual frame buffer device
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENFB_H
+#define _LINUX_XENFB_H
+
+#include <asm/types.h>
+
+/* out events */
+
+#define XENFB_TYPE_MOTION 1
+#define XENFB_TYPE_UPDATE 2
+
+struct xenfb_motion
+{
+	__u8 type;          /* XENFB_TYPE_MOTION */
+	__u16 x;            /* The new x coordinate */
+	__u16 y;            /* The new y coordinate */
+};
+
+struct xenfb_update
+{
+	__u8 type;          /* XENFB_TYPE_UPDATE */
+	__u16 x;            /* source x */
+	__u16 y;            /* source y */
+	__u16 width;        /* rect width */
+	__u16 height;       /* rect height */
+};
+
+union xenfb_out_event
+{
+	__u8 type;
+	struct xenfb_motion motion;
+	struct xenfb_update update;
+	char _[40];
+};
+
+/* in events */
+
+#define XENFB_TYPE_SET_EVENTS 1
+
+#define XENFB_FLAG_MOTION 1
+#define XENFB_FLAG_UPDATE 2
+#define XENFB_FLAG_COPY 4
+#define XENFB_FLAG_FILL 8
+
+struct xenfb_set_events
+{
+	__u8 type;          /* XENFB_TYPE_SET_EVENTS */
+	__u32 flags;        /* combination of XENFB_FLAG_* */
+};
+
+union xenfb_in_event
+{
+	__u8 type;
+	struct xenfb_set_events set_events;
+	char _[40];
+};
+
+/* shared page */
+
+#define XENFB_IN_RING_SIZE (1024 / 40)
+#define XENFB_OUT_RING_SIZE (2048 / 40)
+
+#define XENFB_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring)))
+#define XENFB_RING_REF(ring, idx) (ring)[(idx) % XENFB_RING_SIZE((ring))]
+
+struct xenfb_page
+{
+	__u8 initialized;
+	__u16 width;         /* the width of the framebuffer (in pixels) */
+	__u16 height;        /* the height of the framebuffer (in pixels) */
+	__u32 line_length;   /* the length of a row of pixels (in bytes) */
+	__u32 mem_length;    /* the length of the framebuffer (in bytes) */
+	__u8 depth;          /* the depth of a pixel (in bits) */
+
+	unsigned long pd[2];
+
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+
+	union xenfb_in_event in[XENFB_IN_RING_SIZE];
+	union xenfb_out_event out[XENFB_OUT_RING_SIZE];
+};
+
+void xenfb_resume(void);
+
+#endif
diff -r ec03b24a2d83 -r 6ca424e1867e linux-2.6-xen-sparse/include/linux/xenkbd.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/include/linux/xenkbd.h	Fri Aug 18 16:17:58 2006 -0400
@@ -0,0 +1,82 @@
+/*
+ * linux/include/linux/xenkbd.h -- Xen virtual keyboard/mouse
+ *
+ * Copyright (C) 2005
+ *
+ *      Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef _LINUX_XENKBD_H
+#define _LINUX_XENKBD_H
+
+#include <asm/types.h>
+
+/* in events */
+
+#define XENKBD_TYPE_MOTION  1     /* mouse movement event */
+#define XENKBD_TYPE_BUTTON  2     /* mouse button event */
+#define XENKBD_TYPE_KEY     3     /* keyboard event */
+
+struct xenkbd_motion
+{
+	__u8 type;         /* XENKBD_TYPE_MOTION */
+	__s16 rel_x;       /* relative X motion */
+	__s16 rel_y;       /* relative Y motion */
+};
+
+struct xenkbd_button
+{
+	__u8 type;         /* XENKBD_TYPE_BUTTON */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u8 button;       /* the button (0, 1, 2 is right, middle, left) */
+};
+
+struct xenkbd_key
+{
+	__u8 type;         /* XENKBD_TYPE_KEY */
+	__u8 pressed;      /* 1 if pressed; 0 otherwise */
+	__u16 keycode;     /* KEY_* from linux/input.h */
+};
+
+union xenkbd_in_event
+{
+	__u8 type;
+	struct xenkbd_motion motion;
+	struct xenkbd_button button;
+	struct xenkbd_key key;
+	char _[40];
+};
+
+/* out events */
+
+union xenkbd_out_event
+{
+	__u8 type;
+	char _[40];
+};
+
+/* shared page */
+
+#define XENKBD_IN_RING_SIZE (2048 / 40)
+#define XENKBD_OUT_RING_SIZE (1024 / 40)
+
+#define XENKBD_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring)))
+#define XENKBD_RING_REF(ring, idx) (ring)[(idx) % XENKBD_RING_SIZE((ring))]
+
+struct xenkbd_info
+{
+	__u8 initialized;
+	__u32 in_cons, in_prod;
+	__u32 out_cons, out_prod;
+
+	union xenkbd_in_event in[XENKBD_IN_RING_SIZE];
+	union xenkbd_out_event out[XENKBD_OUT_RING_SIZE];
+};
+
+void xenkbd_resume(void);
+
+#endif

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Paravirt framebuffer kernel infrastructure [1/6]
  2006-08-18 21:05 [PATCH] Paravirt framebuffer kernel infrastructure [1/6] Jeremy Katz
@ 2006-08-21 14:20 ` Markus Armbruster
  2006-08-29 14:39 ` Laurent Vivier
  1 sibling, 0 replies; 3+ messages in thread
From: Markus Armbruster @ 2006-08-21 14:20 UTC (permalink / raw)
  To: Jeremy Katz; +Cc: Ian Pratt, Anthony Liguori, xen-devel, Christian Limpach

Jeremy Katz <katzj@redhat.com> writes:

> Basic kernel space support for virtual framebuffer and keyboard.  This
> is the work Markus did to port Anthony's original code to use xenstore
> and for current kernels.  It should include all of the fixes from the
> last submission

This patch is indeed identical to the one I submitted last.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Paravirt framebuffer kernel infrastructure [1/6]
  2006-08-18 21:05 [PATCH] Paravirt framebuffer kernel infrastructure [1/6] Jeremy Katz
  2006-08-21 14:20 ` Markus Armbruster
@ 2006-08-29 14:39 ` Laurent Vivier
  1 sibling, 0 replies; 3+ messages in thread
From: Laurent Vivier @ 2006-08-29 14:39 UTC (permalink / raw)
  To: Jeremy Katz
  Cc: Ian Pratt, Anthony Liguori, xen-devel, Markus Armbruster,
	Christian Limpach


[-- Attachment #1.1: Type: text/plain, Size: 20642 bytes --]

Hi,

IMHO, I think it should be better to move the refresh timer from kernel to user
space, and to know which part of the image to refresh, a bitmap array should be
easy to use than an event ring.

I propose following patches to do this.

Any comments ?

Regards,
Laurent

Index: xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c
===================================================================
--- xen-3.0-testing.hg.orig/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c
2006-08-29 12:16:49.000000000 +0200
+++ xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c	2006-08-29
16:15:04.000000000 +0200
@@ -24,118 +24,33 @@
 #include <linux/xenfb.h>
 #include <linux/kthread.h>

-static int xenfb_fps = 20;
-static unsigned long xenfb_mem_len = 2 * 1024 * 1024;
+static unsigned long xenfb_mem_len = XENFB_VIDEOMEM_SIZE;

 struct xenfb_mapping
 {
-	struct list_head	next;
 	struct vm_area_struct	*vma;
 	atomic_t		map_refs;
-	int			faults;
 	struct xenfb_info	*info;
 };

 struct xenfb_info
 {
-	struct task_struct		*kthread;
-	wait_queue_head_t		wq;
-
 	unsigned char			*fb;
 	struct fb_fix_screeninfo	*fix;
 	struct fb_var_screeninfo	*var;
 	struct fb_info			*fb_info;
-	struct timer_list		refresh;
-	int				dirty;
 	int				y1, y2;
 	int				x1, x2;

 	struct semaphore		mm_lock;
 	int				nr_pages;
 	struct page			**pages;
-	struct list_head		mappings;

 	unsigned			evtchn;
 	struct xenfb_page		*page;
 	unsigned long 			*mfns;
 };

-static void xenfb_do_update(struct xenfb_info *info,
-			    int x, int y, int w, int h)
-{
-	union xenfb_out_event event;
-	__u32 prod;
-
-	event.type = XENFB_TYPE_UPDATE;
-	event.update.x = x;
-	event.update.y = y;
-	event.update.width = w;
-	event.update.height = h;
-
-	prod = info->page->out_prod;
-	if (prod - info->page->out_cons == XENFB_RING_SIZE(info->page->out))
-		return;		/* ring buffer full, event lost */
-	XENFB_RING_REF(info->page->out, prod) = event;
-	info->page->out_prod = prod + 1;
-
-	notify_remote_via_evtchn(info->evtchn);
-}
-
-static int xenfb_queue_full(struct xenfb_info *info)
-{
-	__u32 cons, prod;
-
-	prod = info->page->out_prod;
-	cons = info->page->out_cons;
-	return prod - cons == XENFB_RING_SIZE(info->page->out);
-}
-
-static void xenfb_update_screen(struct xenfb_info *info)
-{
-	int y1, y2, x1, x2;
-	struct list_head *item;
-	struct xenfb_mapping *map;
-
-	if (xenfb_queue_full(info))
-		return;
-
-	y1 = info->y1;
-	y2 = info->y2;
-	x1 = info->x1;
-	x2 = info->x2;
-	info->dirty = info->y1 = info->y2 = info->x1 = info->x2 = 0;
-	down(&info->mm_lock);
-	list_for_each(item, &info->mappings) {
-		map = list_entry(item, struct xenfb_mapping, next);
-		if (!map->faults)
-			continue;
-		zap_page_range(map->vma, map->vma->vm_start,
-			       map->vma->vm_end - map->vma->vm_start, NULL);
-		map->faults = 0;
-	}
-	up(&info->mm_lock);
-
-	xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
-}
-
-static int xenfb_thread(void *data)
-{
-	struct xenfb_info *info = data;
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&info->wq, &wait);
-	for (;;) {
-		if (kthread_should_stop())
-			break;
-		if (info->dirty)
-			xenfb_update_screen(info);
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule();
-	}
-	remove_wait_queue(&info->wq, &wait);
-	return 0;
-}
-
 static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
 			   struct fb_info *info)
@@ -164,50 +79,24 @@ static int xenfb_setcolreg(unsigned regn
 	return 0;
 }

-static void xenfb_timer(unsigned long data)
+static void xenfb_update_pages(struct xenfb_info *info, int x, int y, int w, int h)
 {
-	struct xenfb_info *info = (struct xenfb_info *)data;
-	info->dirty++;
-	wake_up(&info->wq);
-}
-
-static void xenfb_refresh(struct xenfb_info *info,
-			  int x1, int y1, int w, int h)
-{
-	int y2, x2;
-
-	y2 = y1 + h;
-	x2 = x1 + w;
-	if (info->y2 == 0) {
-		info->y1 = y1;
-		info->y2 = y2;
-	}
-	if (info->x2 == 0) {
-		info->x1 = x1;
-		info->x2 = x2;
-	}
+	int begin, end;
+	int pgnr;

-	if (info->y1 > y1)
-		info->y1 = y1;
-	if (info->y2 < y2)
-		info->y2 = y2;
-	if (info->x1 > x1)
-		info->x1 = x1;
-	if (info->x2 < x2)
-		info->x2 = x2;
+	begin = (y * info->page->line_length + x * (info->page->depth / 8)) >> PAGE_SHIFT;
+	end = ((y + h - 1) * info->page->line_length +
+				((x + w - 1) * (info->page->depth / 8))) >> PAGE_SHIFT;

-	if (timer_pending(&info->refresh))
-		return;
-
-	mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
+	for (pgnr = begin; pgnr <= end; pgnr++)
+		set_bit(pgnr, &info->page->dirty_pages);
 }

 static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
 	struct xenfb_info *info = p->par;
-
 	cfb_fillrect(p, rect);
-	xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
+	xenfb_update_pages(info, rect->dx, rect->dy, rect->width, rect->height);
 }

 static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
@@ -215,7 +104,7 @@ static void xenfb_imageblit(struct fb_in
 	struct xenfb_info *info = p->par;

 	cfb_imageblit(p, image);
-	xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
+	xenfb_update_pages(info, image->dx, image->dy, image->width, image->height);
 }

 static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
@@ -223,7 +112,7 @@ static void xenfb_copyarea(struct fb_inf
 	struct xenfb_info *info = p->par;

 	cfb_copyarea(p, area);
-	xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
+	xenfb_update_pages(info, area->dx, area->dy, area->width, area->height);
 }

 static void xenfb_vm_open(struct vm_area_struct *vma)
@@ -239,7 +128,7 @@ static void xenfb_vm_close(struct vm_are

 	down(&info->mm_lock);
 	if (atomic_dec_and_test(&map->map_refs)) {
-		list_del(&map->next);
+		vma->vm_private_data = NULL;
 		kfree(map);
 	}
 	up(&info->mm_lock);
@@ -252,7 +141,6 @@ static struct page *xenfb_vm_nopage(stru
 	struct xenfb_info *info = map->info;
 	int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
 	struct page *page;
-	int y1, y2;

 	if (pgnr >= info->nr_pages)
 		return NOPAGE_SIGBUS;
@@ -260,13 +148,10 @@ static struct page *xenfb_vm_nopage(stru
 	down(&info->mm_lock);
 	page = info->pages[pgnr];
 	get_page(page);
-	map->faults++;

-	y1 = pgnr * PAGE_SIZE / info->fix->line_length;
-	y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length;
-	if (y2 > info->var->yres)
-		y2 = info->var->yres;
-	xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1);
+	set_bit(pgnr, &info->page->dirty_pages);
+	zap_page_range(map->vma, map->vma->vm_start, map->vma->vm_end -
map->vma->vm_start, NULL);
+
 	up(&info->mm_lock);

 	if (type)
@@ -309,10 +194,8 @@ static int xenfb_mmap(struct fb_info *fb
 	memset(map, 0, sizeof(*map));

 	map->vma = vma;
-	map->faults = 0;
 	map->info = info;
 	atomic_set(&map->map_refs, 1);
-	list_add(&map->next, &info->mappings);
 	vma->vm_ops = &xenfb_vm_ops;
 	vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
 	vma->vm_private_data = map;
@@ -375,8 +258,6 @@ static int __init xenfb_probe(void)
 		return -ENOMEM;
 	memset(info, 0, sizeof(*info));

-	INIT_LIST_HEAD(&info->mappings);
-
 	info->fb = vmalloc(xenfb_mem_len);
 	if (info->fb == NULL)
 		goto error;
@@ -416,6 +297,8 @@ static int __init xenfb_probe(void)
 	info->page->mem_length = xenfb_mem_len;
 	info->page->in_cons = info->page->in_prod = 0;
 	info->page->out_cons = info->page->out_prod = 0;
+	for (i = 0; i < XENFB_DIRTY_PAGES_SIZE; i++)
+		info->page->dirty_pages[i] = 0xFF;

 	ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
 					0, "xenfb", info);
@@ -464,12 +347,6 @@ static int __init xenfb_probe(void)
 	info->var = &fb_info->var;

 	init_MUTEX(&info->mm_lock);
-	init_waitqueue_head(&info->wq);
-	init_timer(&info->refresh);
-	info->refresh.function = xenfb_timer;
-	info->refresh.data = (unsigned long)info;
-
-	info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");

 	ret = register_framebuffer(fb_info);
 	if (ret)
@@ -518,30 +395,6 @@ static int __init xenfb_probe(void)
 	return -ENODEV;
 }

-void xenfb_resume(void)
-{
-#if 0 /* FIXME */
-	int i, ret;
-
-	xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn);
-	for (i = 0; i < xenfb_info->nr_pages; i++)
-		xenfb_info->mfns[i] = vmalloc_to_mfn(xenfb_info->fb + i * PAGE_SIZE);
-	xenfb_info->page->pd[0] = vmalloc_to_mfn(xenfb_info->mfns);
-
-	if (xenfb_irq)
-		unbind_from_irqhandler(xenfb_irq, NULL);
-
-	printk("xenfb: resume(%d)\n", xen_start_info->fbdev_evtchn);
-	ret = bind_evtchn_to_irqhandler(xen_start_info->fbdev_evtchn,
-					xenfb_event_handler, 0, "xenfb", xenfb_info);
-	if (ret <= 0)
-		return;
-	xenfb_irq = ret;
-#else
-	printk(KERN_DEBUG "xenfb_resume not implemented\n");
-#endif
-}
-
 static int __init xenfb_init(void)
 {
 	return xenfb_probe();
Index: xen-3.0-testing.hg/linux-2.6.16.13-xen/include/linux/xenfb.h
===================================================================
--- xen-3.0-testing.hg.orig/linux-2.6.16.13-xen/include/linux/xenfb.h	2006-08-29
12:16:49.000000000 +0200
+++ xen-3.0-testing.hg/linux-2.6.16.13-xen/include/linux/xenfb.h	2006-08-29
12:36:06.000000000 +0200
@@ -27,20 +27,10 @@ struct xenfb_motion
 	__u16 y;            /* The new y coordinate */
 };

-struct xenfb_update
-{
-	__u8 type;          /* XENFB_TYPE_UPDATE */
-	__u16 x;            /* source x */
-	__u16 y;            /* source y */
-	__u16 width;        /* rect width */
-	__u16 height;       /* rect height */
-};
-
 union xenfb_out_event
 {
 	__u8 type;
 	struct xenfb_motion motion;
-	struct xenfb_update update;
 	char _[40];
 };

@@ -69,11 +59,14 @@ union xenfb_in_event
 /* shared page */

 #define XENFB_IN_RING_SIZE (1024 / 40)
-#define XENFB_OUT_RING_SIZE (2048 / 40)
+#define XENFB_OUT_RING_SIZE (1024 / 40)

 #define XENFB_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring)))
 #define XENFB_RING_REF(ring, idx) (ring)[(idx) % XENFB_RING_SIZE((ring))]

+#define XENFB_VIDEOMEM_SIZE	(2 * 1024 * 1024)
+#define XENFB_DIRTY_PAGES_SIZE	((((XENFB_VIDEOMEM_SIZE + 4096 - 1)/ 4096) + 7) / 8)
+
 struct xenfb_page
 {
 	__u8 initialized;
@@ -90,6 +83,8 @@ struct xenfb_page

 	union xenfb_in_event in[XENFB_IN_RING_SIZE];
 	union xenfb_out_event out[XENFB_OUT_RING_SIZE];
+
+	__u8 dirty_pages[XENFB_DIRTY_PAGES_SIZE];
 };

 void xenfb_resume(void);

Index: vncfb/sdlfb.c
===================================================================
--- vncfb.orig/sdlfb.c	2006-08-29 12:17:02.000000000 +0200
+++ vncfb/sdlfb.c	2006-08-29 14:16:33.000000000 +0200
@@ -7,13 +7,17 @@ typedef unsigned long kernel_ulong_t;
 #include <linux/input.h>
 #include "xenfb.h"

+extern char *get_bitmap(struct xenfb *xenfb, int *size);
+
+#define IPS	(30)
+
 struct data
 {
 	SDL_Surface *dst;
 	SDL_Surface *src;
 };

-void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
+static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
 {
 	struct data *data = xenfb->user_data;
 	SDL_Rect r = { x, y, width, height };
@@ -21,6 +25,65 @@ void sdl_update(struct xenfb *xenfb, int
 	SDL_UpdateRect(data->dst, x, y, width, height);
 }

+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+	__asm__ __volatile__( "lock ; "
+			"btrl %2,%1\n\tsbbl %0,%0"
+			:"=r" (oldbit),"+m" (*(volatile long *) addr)
+			:"Ir" (nr) : "memory");
+	return oldbit;
+}
+
+static void sdl_memory_udpate(struct xenfb *xenfb, int begin, int end)
+{
+	int y1, y2;
+	begin *= 4096;
+	end *= 4096;
+
+	y1 = begin / xenfb->row_stride;
+	y2 = end / xenfb->row_stride;
+
+	if (y1 != y2)
+		sdl_update(xenfb, 0, y1, xenfb->width, y2 - y1);
+	else {
+		int x1, x2;
+		x1 = (begin - y1 * xenfb->row_stride) / (xenfb->depth / 8);
+		x2 = (begin - y2 * xenfb->row_stride) / (xenfb->depth / 8);
+		sdl_update(xenfb, x1, y1, xenfb->width - x1, 1);
+		sdl_update(xenfb, x1, y1 + 1, x2 - x1 + 1, y2 - y1 - 1);
+		sdl_update(xenfb, 0, y2, x2 - 1, 1);
+	}
+}
+
+static Uint32 refresh_handler(Uint32 interval, void *param)
+{
+#define WSIZE	(sizeof(unsigned long)*8)
+	struct xenfb * xenfb = param;
+	int size;
+	unsigned long *bitmap;
+	int i, j;
+	int begin = -1;
+	bitmap = (unsigned long*)get_bitmap(xenfb, &size);
+	for (i = 0; i < size / sizeof(unsigned long); i++) {
+		for (j = 0; j < WSIZE; j++) {
+			if (test_and_clear_bit(j, bitmap + i)) {
+				if (begin == -1)
+					begin = i * WSIZE + j;
+			} else if (begin != -1) {
+				sdl_memory_udpate(xenfb,
+					  	begin,
+					  	i * WSIZE + j);
+				begin = -1;
+			}
+		}
+	}
+	if (begin != -1) {
+		sdl_memory_udpate(xenfb, begin, size * WSIZE - 1);
+	}
+	return interval;	
+}
+
 int sdl2linux[1024] = {
 	[9] = KEY_ESC,
 	[67] = KEY_F1,
@@ -132,13 +195,11 @@ int sdl2linux[1024] = {
 int main(int argc, char **argv)
 {
 	struct xenfb *xenfb;
-	int fd;
 	int domid;
-	fd_set readfds;
 	struct data data;
 	SDL_Rect r;
-	struct timeval tv = { 0, 500 };
 	int do_quit = 0;
+	SDL_TimerID refreshTimer;


 	if (argc != 2)
@@ -153,12 +214,10 @@ int main(int argc, char **argv)
 	if (!xenfb_set_domid(xenfb, domid))
 		return 1;

-	SDL_Init(SDL_INIT_VIDEO);
-
-	fd = xenfb_get_fileno(xenfb);
+	SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER);

 	data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
-				    SDL_SWSURFACE);
+				    SDL_HWSURFACE);
 	data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
 					    xenfb->width, xenfb->height,
 					    xenfb->depth, xenfb->row_stride,
@@ -170,15 +229,12 @@ int main(int argc, char **argv)
 	SDL_BlitSurface(data.src, &r, data.dst, &r);
 	SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);

-	xenfb->update = sdl_update;
 	xenfb->user_data = &data;

-	FD_ZERO(&readfds);
-	FD_SET(fd, &readfds);
-
 	SDL_ShowCursor(0);

-	while (!do_quit && select(fd + 1, &readfds, NULL, NULL, &tv) != -1) {
+	refreshTimer = SDL_AddTimer(1000 / IPS, refresh_handler, xenfb);
+	while (!do_quit) {
 		SDL_Event event;

 		while (SDL_PollEvent(&event)) {
@@ -207,15 +263,9 @@ int main(int argc, char **argv)
 				break;
 			}
 		}
-		if (FD_ISSET(fd, &readfds))
-			xenfb_on_incoming(xenfb);
-
-		FD_ZERO(&readfds);
-		FD_SET(fd, &readfds);
-
-		tv = (struct timeval){0, 500};
 	}

+	SDL_RemoveTimer(refreshTimer);
 	xenfb_delete(xenfb);

 	SDL_Quit();
Index: vncfb/vncfb.c
===================================================================
--- vncfb.orig/vncfb.c	2006-08-28 18:20:00.000000000 +0200
+++ vncfb/vncfb.c	2006-08-29 14:45:52.000000000 +0200
@@ -1,7 +1,15 @@
+#include <signal.h>
+#include <sys/time.h>
 #include <malloc.h>
 #include <rfb/rfb.h>
 #include "xenfb.h"

+static struct xenfb *xenfb;
+
+extern char *get_bitmap(struct xenfb *xenfb, int *size);
+
+#define IPS	(30)
+
 static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
 {
 	extern uint32_t gdk_linux_mapping[0x10000];
@@ -23,7 +31,6 @@ static void on_ptr_event(int buttonMask,
 		for (i = 0; i < 8; i++) {
 			if ((last_button & (1 << i)) !=
 			    (buttonMask & (1 << i))) {
-				printf("%d %d\n", buttonMask & (1 << i), i);
 				xenfb_send_button(xenfb, buttonMask & (1 << i),
 						  2 - i);
 			}
@@ -52,16 +59,72 @@ static void vnc_update(struct xenfb *xen
 	rfbMarkRectAsModified(server, x, y, x + w, y + h);
 }

+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+	int oldbit;
+	__asm__ __volatile__( "lock ; "
+			"btrl %2,%1\n\tsbbl %0,%0"
+			:"=r" (oldbit),"+m" (*(volatile long *) addr)
+			:"Ir" (nr) : "memory");
+	return oldbit;
+}
+
+static void vnc_memory_udpate(struct xenfb *xenfb, int begin, int end)
+{
+	int y1, y2;
+	begin *= 4096;
+	end *= 4096;
+
+	y1 = begin / xenfb->row_stride;
+	y2 = end / xenfb->row_stride;
+
+	if (y1 != y2)
+		vnc_update(xenfb, 0, y1, xenfb->width, y2 - y1);
+	else {
+		int x1, x2;
+		x1 = (begin - y1 * xenfb->row_stride) / (xenfb->depth / 8);
+		x2 = (begin - y2 * xenfb->row_stride) / (xenfb->depth / 8);
+		vnc_update(xenfb, x1, y1, xenfb->width - x1, 1);
+		vnc_update(xenfb, x1, y1 + 1, x2 - x1 + 1, y2 - y1 - 1);
+		vnc_update(xenfb, 0, y2, x2 - 1, 1);
+	}
+}
+
+static void refresh_handler(int sig, siginfo_t *info, void* env)
+{
+#define WSIZE	(sizeof(unsigned long)*8)
+	int size;
+	unsigned long *bitmap;
+	int i, j;
+	int begin = -1;
+	bitmap = (unsigned long*)get_bitmap(xenfb, &size);
+	for (i = 0; i < size / sizeof(unsigned long); i++) {
+		for (j = 0; j < WSIZE; j++) {
+			if (test_and_clear_bit(j, bitmap + i)) {
+				if (begin == -1)
+					begin = i * WSIZE + j;
+			} else if (begin != -1) {
+				vnc_memory_udpate(xenfb,
+					  	begin,
+					  	i * WSIZE + j);
+				begin = -1;
+			}
+		}
+	}
+	if (begin != -1) {
+		vnc_memory_udpate(xenfb, begin, size * WSIZE - 1);
+	}
+}
+
 int main(int argc, char **argv)
 {
 	rfbScreenInfoPtr server;
 	char *fake_argv[3] = { "vncfb", "-rfbport", "5901" };
 	int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
 	int domid;
-	struct xenfb *xenfb;
-	fd_set readfds;
-	int fd;
 	char buffer[1024];
+	struct sigaction action;
+	struct itimerval timer;

 	if (argc != 2)
 		BUG();
@@ -85,7 +148,6 @@ int main(int argc, char **argv)
 		BUG();

 	xenfb->user_data = server;
-	xenfb->update = vnc_update;

 	server->serverFormat.redShift = 16;
 	server->serverFormat.greenShift = 8;
@@ -96,21 +158,20 @@ int main(int argc, char **argv)
 	server->screenData = xenfb;
 	rfbInitServer(server);

-	rfbRunEventLoop(server, -1, TRUE);
-
-	fd = xenfb_get_fileno(xenfb);

-	FD_ZERO(&readfds);
-	FD_SET(fd, &readfds);
+	memset(&action, 0, sizeof(action));
+	action.sa_sigaction = refresh_handler;
+	action.sa_flags = SA_RESTART;
+	sigemptyset(&action.sa_mask);
+	sigaction(SIGALRM, &action, NULL);
+
+	timer.it_value.tv_sec = 0;
+	timer.it_value.tv_usec = 100000 / IPS;
+	timer.it_interval.tv_sec = timer.it_value.tv_sec;
+	timer.it_interval.tv_usec = timer.it_value.tv_usec;
+	setitimer(ITIMER_REAL, &timer, NULL);

-	while (select(fd + 1, &readfds, NULL, NULL, NULL) != -1) {
-		if (FD_ISSET(fd, &readfds)) {
-			xenfb_on_incoming(xenfb);
-		}
-		
-		FD_ZERO(&readfds);
-		FD_SET(fd, &readfds);
-	}
+	rfbRunEventLoop(server, 100000 / IPS, FALSE);

 	rfbScreenCleanup(server);
 	xenfb_delete(xenfb);
Index: vncfb/xenfb.c
===================================================================
--- vncfb.orig/xenfb.c	2006-08-29 12:17:02.000000000 +0200
+++ vncfb/xenfb.c	2006-08-29 14:42:41.000000000 +0200
@@ -69,15 +69,6 @@ struct xenfb *xenfb_new(void)
 	return &xenfb->pub;
 }

-int xenfb_get_fileno(struct xenfb *xenfb_pub)
-{
-	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
-	if (xenfb->domid == -1)
-		return -1;
-
-	return xenfb->fd;
-}
-
 static void xenfb_unset_domid(struct xenfb_private *xenfb)
 {
 	struct ioctl_evtchn_unbind unbind;
@@ -357,10 +348,10 @@ bool xenfb_set_domid(struct xenfb *xenfb
 	return false;
 }

-static void xenfb_update(struct xenfb_private *xenfb, int x, int y, int width,
int height)
+char *get_bitmap(struct xenfb_private *xenfb, int *size)
 {
-	if (xenfb->pub.update)
-		xenfb->pub.update(&xenfb->pub, x, y, width, height);
+	*size = XENFB_DIRTY_PAGES_SIZE;
+	return xenfb->fb_info->dirty_pages;
 }

 static void xenfb_on_fb_event(struct xenfb_private *xenfb)
@@ -375,7 +366,6 @@ static void xenfb_on_fb_event(struct xen

 		switch (event->type) {
 		case XENFB_TYPE_UPDATE:
-			xenfb_update(xenfb, event->update.x, event->update.y, event->update.width,
event->update.height);
 			break;
 		}
 	}
Index: vncfb/xenfb.h
===================================================================
--- vncfb.orig/xenfb.h	2006-07-21 18:21:33.000000000 +0200
+++ vncfb/xenfb.h	2006-08-29 13:53:20.000000000 +0200
@@ -14,8 +14,6 @@ struct xenfb
 	int height;

 	void *user_data;
-
-	void (*update)(struct xenfb *xenfb, int x, int y, int width, int height);
 };

 struct xenfb *xenfb_new(void);

-- 
                Laurent.Vivier@bull.net
         Bull, Architect of an Open World (TM)
+----- "Any sufficiently advanced technology is ----+
| indistinguishable from magic." - Arthur C. Clarke |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-08-29 14:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-18 21:05 [PATCH] Paravirt framebuffer kernel infrastructure [1/6] Jeremy Katz
2006-08-21 14:20 ` Markus Armbruster
2006-08-29 14:39 ` Laurent Vivier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.