I ported Anthony Liguori''s virtual frame buffer to current kernels and converted it to use Xenstore. Here''s a brief sketch of how it works. http://wiki.xensource.com/xenwiki/VirtualFramebuffer has more detail, and also also outlines future work, but the stuff on startup there no longer applies. The VFB''s architecture is comparable to the common split device driver architecture: xenfb and xenkbd modules serve as frontend in domU, and the user space vncfb server serves as backend in dom0. xenfb and xenkbd don''t use the Xenbus infrastructure for frontends, because it doesn''t quite fit. They publish their shared memory page and event channel in Xenstore entries {vfb,vkbd}/{page-ref,event-channel}. As usual, the shared memory page contains information about the device, input event ring and output event ring. xenkbd defines pointer motion events, button events and keyboard events. xenfb defines events to optionally signal frame buffer page updates. vncfb runs in dom0. It takes the domain to watch as argument. It then watches /local/domain/DOMID/{vfb,vkbd} until everything it needs is there. It maps the shared memory and connects the event channels. Use of event ring and event channel follows the common patterns. xenfb actually shares more memory than just a page. It also shares the frame buffer itself. The page shared through Xenstore has enough information so that vncfb can map the frame buffer as well. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jun-26 13:39 UTC
[Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
Derived from http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle Converted to Xenstore and ported to current kernels. Signed-off-by: Markus Armbruster <armbru@redhat.com> diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c --- a/arch/i386/kernel/setup-xen.c Fri Jun 16 19:34:13 2006 +0200 +++ b/arch/i386/kernel/setup-xen.c Fri Jun 23 10:07:51 2006 +0200 @@ -1787,8 +1787,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 d8434a6fdd05 drivers/xen/Kconfig --- a/drivers/xen/Kconfig Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Kconfig Fri Jun 23 10:07:51 2006 +0200 @@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP to a character device, allowing device prototyping in application space. Odds are that you want to say N 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 d8434a6fdd05 drivers/xen/Makefile --- a/drivers/xen/Makefile Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP) += blkt obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/xenfb.c Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,579 @@ +/* + * 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 cons, prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + /* FIXME barriers */ + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); + prod = XENFB_MASK_RING(prod + 1, info->page->out); + + if (prod == cons) + return; + + memcpy(&info->page->out[prod], &event, sizeof(event)); + info->page->out_prod = prod; + + notify_remote_via_evtchn(info->evtchn); +} + +static int xenfb_queue_full(struct xenfb_info *info) +{ + __u32 cons, prod; + + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); + prod = XENFB_MASK_RING(prod + 1, info->page->out); + + return (prod == cons); +} + +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; + + /* FIXME barriers */ + prod = XENFB_MASK_RING(info->page->in_prod, info->page->in); + cons = XENFB_MASK_RING(info->page->in_cons, info->page->in); + + if (prod == cons) + return IRQ_HANDLED; + + for (; cons!=prod; cons = XENFB_MASK_RING(cons+1, info->page->in)) { + union xenfb_in_event *event; + event = &info->page->in[cons]; + notify_remote_via_evtchn(info->evtchn); + } + + 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; + xenbus_transaction_t 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->width = 800; + info->page->height = 600; + info->page->depth = 32; // FIXME was 24; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + + 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; + + 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) + 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; + +#if 0 + xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn); +#endif + 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 0 + if (xenfb_irq) + unbind_from_irqhandler(xenfb_irq, NULL); +#endif + +#if 0 + 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); +#endif + 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 d8434a6fdd05 drivers/xen/xenkbd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/xenkbd.c Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,206 @@ +/* + * 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; + + /* FIXME barriers */ + prod = XENKBD_MASK_RING(info->in_prod, info->in); + cons = XENKBD_MASK_RING(info->in_cons, info->in); + + if (prod == cons) + return IRQ_HANDLED; + + for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->in)) { + union xenkbd_in_event *event; + + event = &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); + + 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; + xenbus_transaction_t 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 */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_register_device(input_dev); + + 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) + 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 + 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"); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jun-26 13:40 UTC
[Xen-devel] [PATCH 2/2] Virtual frame buffer: user space backend
Straightforward conversion to Xenstore. Applies to hg repository at http://hg.codemonkey.ws/vncfb Signed-off-by: Markus Armbruster <armbru@redhat.com> diff -r f67e0a168879 Makefile --- a/Makefile Tue Jan 24 16:14:00 2006 -0500 +++ b/Makefile Mon Jun 26 09:20:04 2006 +0200 @@ -2,7 +2,7 @@ CFLAGS += -g -Wall ifneq ($(XENDIR),) CFLAGS += -I$(XENDIR)/tools/libxc -I$(XENDIR)/linux-2.6.12-xenU/include -LDFLAGS += -L$(XENDIR)/tools/libxc +LDFLAGS += -L$(XENDIR)/tools/libxc -L$(XENDIR)/tools/xenstore endif all: vncfb sdlfb @@ -13,7 +13,7 @@ sdlfb: sdlfb.o xenfb.o sdlfb: sdlfb.o xenfb.o sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore clean: $(RM) *.o *~ vncfb @@ -22,4 +22,4 @@ keymapping.o: CFLAGS += $(shell pkg-conf vncfb: vncfb.o xenfb.o keymapping.o vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore diff -r f67e0a168879 xenfb.c --- a/xenfb.c Tue Jan 24 16:14:00 2006 -0500 +++ b/xenfb.c Mon Jun 26 09:20:04 2006 +0200 @@ -16,6 +16,7 @@ #include <stdio.h> #include <string.h> #include <time.h> +#include <xs.h> #include "xenfb.h" @@ -140,13 +141,46 @@ static int xenfb_kbd_event(struct xenfb_ return -1; } +static char *xenfb_path_in_dom(struct xs_handle *h, + unsigned domid, const char *path, + char *buffer, size_t size) +{ + char *domp = xs_get_domain_path(h, domid); + int n = snprintf(buffer, size, "%s/%s", domp, path); + free(domp); + if (n >= size) + return NULL; + return buffer; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid, + const char *path, const char *fmt, + void *dest) +{ + char buffer[1024]; + char *p; + int ret; + + p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer)); + p = xs_read(xsh, XBT_NULL, p, NULL); + if (!p) + return -ENOENT; + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) + return -EDOM; + return 0; +} + bool xenfb_set_domid(struct xenfb *xenfb_pub, int domid) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; char buffer[1024]; - FILE *f; + struct xs_handle *xsh; + unsigned dummy; + int ret; + char *p, **vec; struct ioctl_evtchn_bind_interdomain bind; - time_t timeout; if (xenfb->domid != -1) { xenfb_unset_domid(xenfb); @@ -154,47 +188,53 @@ bool xenfb_set_domid(struct xenfb *xenfb return true; } - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.mfn", domid); - timeout = time(0); - do { - f = fopen(buffer, "r"); - if (!f) { - struct timeval tv = { 0, 500 }; - select(0, NULL, NULL, NULL, &tv); - } - } while (f == NULL && (timeout + 10) > time(0)); - - if (!f || fscanf(f, "%lu", &xenfb->fbdev_mfn) != 1) + xsh = xs_daemon_open_readonly(); + if (!xsh) + goto error; + + p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->fbdev_evtchn) != 1) + p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.mfn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%lu", &xenfb->kbd_mfn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->kbd_evtchn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); + + for (;;) { + ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu", + &xenfb->fbdev_mfn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vfb/event-channel", "%u", + &xenfb->fbdev_evtchn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/page-ref", "%lu", + &xenfb->kbd_mfn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/event-channel", "%u", + &xenfb->kbd_evtchn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + break; + + wait: + printf("Waiting...\n"); + vec = xs_read_watch(xsh, &dummy); + if (!vec) + goto error; + free(vec); + } + xs_daemon_close(xsh); + xsh = NULL; printf("%d, %d, %d\n", xenfb->fd, xenfb->fbdev_evtchn, domid); @@ -312,9 +352,9 @@ bool xenfb_set_domid(struct xenfb *xenfb } error: printf("%d\n", __LINE__); - if (f) { - int serrno = errno; - fclose(f); + if (xsh) { + int serrno = errno; + xs_daemon_close(xsh); errno = serrno; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
This is a repost. We clearly need some review to move forward. I ported Anthony Liguori''s virtual frame buffer to current kernels and converted it to use Xenstore. Here''s a brief sketch of how it works. http://wiki.xensource.com/xenwiki/VirtualFramebuffer has more detail, and also also outlines future work, but the stuff on startup there no longer applies. The VFB''s architecture is comparable to the common split device driver architecture: xenfb and xenkbd modules serve as frontend in domU, and the user space vncfb server serves as backend in dom0. xenfb and xenkbd don''t use the Xenbus infrastructure for frontends, because it doesn''t quite fit. They publish their shared memory page and event channel in Xenstore entries {vfb,vkbd}/{page-ref,event-channel}. As usual, the shared memory page contains information about the device, input event ring and output event ring. xenkbd defines pointer motion events, button events and keyboard events. xenfb defines events to optionally signal frame buffer page updates. vncfb runs in dom0. It takes the domain to watch as argument. It then watches /local/domain/DOMID/{vfb,vkbd} until everything it needs is there. It maps the shared memory and connects the event channels. Use of event ring and event channel follows the common patterns. xenfb actually shares more memory than just a page. It also shares the frame buffer itself. The page shared through Xenstore has enough information so that vncfb can map the frame buffer as well. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-07 07:18 UTC
[Xen-devel] Re: [PATCH 1/2] Virtual frame buffer: frontend
Derived from http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle Converted to Xenstore and ported to current kernels. Signed-off-by: Markus Armbruster <armbru@redhat.com> diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c --- a/arch/i386/kernel/setup-xen.c Fri Jun 16 19:34:13 2006 +0200 +++ b/arch/i386/kernel/setup-xen.c Fri Jun 23 10:07:51 2006 +0200 @@ -1787,8 +1787,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 d8434a6fdd05 drivers/xen/Kconfig --- a/drivers/xen/Kconfig Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Kconfig Fri Jun 23 10:07:51 2006 +0200 @@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP to a character device, allowing device prototyping in application space. Odds are that you want to say N 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 d8434a6fdd05 drivers/xen/Makefile --- a/drivers/xen/Makefile Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP) += blkt obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/xenfb.c Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,579 @@ +/* + * 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 cons, prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + /* FIXME barriers */ + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); + prod = XENFB_MASK_RING(prod + 1, info->page->out); + + if (prod == cons) + return; + + memcpy(&info->page->out[prod], &event, sizeof(event)); + info->page->out_prod = prod; + + notify_remote_via_evtchn(info->evtchn); +} + +static int xenfb_queue_full(struct xenfb_info *info) +{ + __u32 cons, prod; + + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); + prod = XENFB_MASK_RING(prod + 1, info->page->out); + + return (prod == cons); +} + +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; + + /* FIXME barriers */ + prod = XENFB_MASK_RING(info->page->in_prod, info->page->in); + cons = XENFB_MASK_RING(info->page->in_cons, info->page->in); + + if (prod == cons) + return IRQ_HANDLED; + + for (; cons!=prod; cons = XENFB_MASK_RING(cons+1, info->page->in)) { + union xenfb_in_event *event; + event = &info->page->in[cons]; + notify_remote_via_evtchn(info->evtchn); + } + + 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; + xenbus_transaction_t 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->width = 800; + info->page->height = 600; + info->page->depth = 32; // FIXME was 24; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + + 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; + + 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) + 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; + +#if 0 + xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn); +#endif + 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 0 + if (xenfb_irq) + unbind_from_irqhandler(xenfb_irq, NULL); +#endif + +#if 0 + 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); +#endif + 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 d8434a6fdd05 drivers/xen/xenkbd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/Makefile Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/xenkbd.c Fri Jun 23 10:07:51 2006 +0200 @@ -0,0 +1,206 @@ +/* + * 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; + + /* FIXME barriers */ + prod = XENKBD_MASK_RING(info->in_prod, info->in); + cons = XENKBD_MASK_RING(info->in_cons, info->in); + + if (prod == cons) + return IRQ_HANDLED; + + for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->in)) { + union xenkbd_in_event *event; + + event = &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); + + 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; + xenbus_transaction_t 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 */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_register_device(input_dev); + + 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) + 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 + 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"); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-07 07:18 UTC
[Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
Straightforward conversion to Xenstore. Applies to hg repository at http://hg.codemonkey.ws/vncfb Signed-off-by: Markus Armbruster <armbru@redhat.com> diff -r f67e0a168879 Makefile --- a/Makefile Tue Jan 24 16:14:00 2006 -0500 +++ b/Makefile Mon Jun 26 09:20:04 2006 +0200 @@ -2,7 +2,7 @@ CFLAGS += -g -Wall ifneq ($(XENDIR),) CFLAGS += -I$(XENDIR)/tools/libxc -I$(XENDIR)/linux-2.6.12-xenU/include -LDFLAGS += -L$(XENDIR)/tools/libxc +LDFLAGS += -L$(XENDIR)/tools/libxc -L$(XENDIR)/tools/xenstore endif all: vncfb sdlfb @@ -13,7 +13,7 @@ sdlfb: sdlfb.o xenfb.o sdlfb: sdlfb.o xenfb.o sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore clean: $(RM) *.o *~ vncfb @@ -22,4 +22,4 @@ keymapping.o: CFLAGS += $(shell pkg-conf vncfb: vncfb.o xenfb.o keymapping.o vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore diff -r f67e0a168879 xenfb.c --- a/xenfb.c Tue Jan 24 16:14:00 2006 -0500 +++ b/xenfb.c Mon Jun 26 09:20:04 2006 +0200 @@ -16,6 +16,7 @@ #include <stdio.h> #include <string.h> #include <time.h> +#include <xs.h> #include "xenfb.h" @@ -140,13 +141,46 @@ static int xenfb_kbd_event(struct xenfb_ return -1; } +static char *xenfb_path_in_dom(struct xs_handle *h, + unsigned domid, const char *path, + char *buffer, size_t size) +{ + char *domp = xs_get_domain_path(h, domid); + int n = snprintf(buffer, size, "%s/%s", domp, path); + free(domp); + if (n >= size) + return NULL; + return buffer; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid, + const char *path, const char *fmt, + void *dest) +{ + char buffer[1024]; + char *p; + int ret; + + p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer)); + p = xs_read(xsh, XBT_NULL, p, NULL); + if (!p) + return -ENOENT; + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) + return -EDOM; + return 0; +} + bool xenfb_set_domid(struct xenfb *xenfb_pub, int domid) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; char buffer[1024]; - FILE *f; + struct xs_handle *xsh; + unsigned dummy; + int ret; + char *p, **vec; struct ioctl_evtchn_bind_interdomain bind; - time_t timeout; if (xenfb->domid != -1) { xenfb_unset_domid(xenfb); @@ -154,47 +188,53 @@ bool xenfb_set_domid(struct xenfb *xenfb return true; } - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.mfn", domid); - timeout = time(0); - do { - f = fopen(buffer, "r"); - if (!f) { - struct timeval tv = { 0, 500 }; - select(0, NULL, NULL, NULL, &tv); - } - } while (f == NULL && (timeout + 10) > time(0)); - - if (!f || fscanf(f, "%lu", &xenfb->fbdev_mfn) != 1) + xsh = xs_daemon_open_readonly(); + if (!xsh) + goto error; + + p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->fbdev_evtchn) != 1) + p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.mfn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%lu", &xenfb->kbd_mfn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->kbd_evtchn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); + + for (;;) { + ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu", + &xenfb->fbdev_mfn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vfb/event-channel", "%u", + &xenfb->fbdev_evtchn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/page-ref", "%lu", + &xenfb->kbd_mfn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/event-channel", "%u", + &xenfb->kbd_evtchn); + if (ret == -ENOENT) + goto wait; + if (ret < 0) + goto error; + break; + + wait: + printf("Waiting...\n"); + vec = xs_read_watch(xsh, &dummy); + if (!vec) + goto error; + free(vec); + } + xs_daemon_close(xsh); + xsh = NULL; printf("%d, %d, %d\n", xenfb->fd, xenfb->fbdev_evtchn, domid); @@ -312,9 +352,9 @@ bool xenfb_set_domid(struct xenfb *xenfb } error: printf("%d\n", __LINE__); - if (f) { - int serrno = errno; - fclose(f); + if (xsh) { + int serrno = errno; + xs_daemon_close(xsh); errno = serrno; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-07 16:45 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote:> Derived from > http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle > > Converted to Xenstore and ported to current kernels.This looks good. Could you address the following issues: - the patch which defined struct xenfb_page seems to be missing - handling of the ring indexes: + we generally prefer to store ring indexes in their unmasked form, it makes debugging easier and it allows the ring to be used to its full capacity instead of requiring leaving one slot empty to be able distinguish empty/full + unless I misread the code, the producer (for frontend to backend messages) seems to write to out_prod + 1 > out_cons, then increment out_prob (xenfb_do_update) and then the consumer processes entries from out_cons upto but not include the updated out_prod (xenfb_on_fb_event) -- the producer for the other way around (backend to frontend, xenfb_fb_event) seems to be correcter. + the lack of barriers -- /* FIXME barriers */ doesn''t really cut it ;-) ==> I would suggest looking at the block or net frontend/backend drivers and copy/pasting some code from there... - xenbus transactions can fail and there''s no code to retry failed transactions Additionally, I think that the dirty region protocol doesn''t really perform too well in quite simple usage cases like having video play in one corner of the screen and the mouse being moved in the opposite corner. It''s probably good enough for this version and supporting this protocol in the future isn''t too bad. I''m looking forward to seeing a new version of this patch, thanks! christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-07 16:57 UTC
Re: [Xen-devel] [PATCH 2/2] Virtual frame buffer: user space backend
On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote:> Straightforward conversion to Xenstore. > > Applies to hg repository at http://hg.codemonkey.ws/vncfbThis also looks ok, two of the frontend issues apply here as well: - handling of the ring indexes (masking of indexes and use of barriers) - xenbus transactions can fail and there''s no code to retry failed transactions Additionally, it would be good to use the vnc server code which we''re going to use in the updated ioemu. Sharing code for the framebuffers for pv and non-pv domains is good and we don''t want the dependency on libvncserver anymore and the qemu vnc code is much compacter. You''ll want to grab the vnc files which come with qemu 0.8.1 (http://xenbits.xensource.com/chris/ioemu-cvs-qemu-0.8.1.tar.bz2) and then apply the following two patches: http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=18f45f0721d8;file=vnc-cleanup;style=raw http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=bc42f3c29c74;file=vnc-fixes;style=raw Ideally, we''d move qemu''s vnc support into a library to make it reusable. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2006-Jul-07 17:31 UTC
[Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On Fri, 07 Jul 2006 17:57:52 +0100, Christian Limpach wrote:> On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: >> Straightforward conversion to Xenstore. >> >> Applies to hg repository at http://hg.codemonkey.ws/vncfb > > Ideally, we''d move qemu''s vnc support into a library to make it reusable.I had considered this. It''s a little awkward since b/c of the dependence on QEMU''s async IO routines but it wouldn''t be that bad. At this point, it probably makes most sense to communicate the linear offsets within the framebuffer that are dirty instead of computing a rect. Since the QEMU VNC code already does rectangle finding and maintains dirty tile bitmap, we don''t really have to attempt to find the rect in the frontend at all. Regards, Anthony Liguori _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-07 18:33 UTC
Re: [Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On 7/7/06, Anthony Liguori <anthony@codemonkey.ws> wrote:> On Fri, 07 Jul 2006 17:57:52 +0100, Christian Limpach wrote: > > > On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: > >> Straightforward conversion to Xenstore. > >> > >> Applies to hg repository at http://hg.codemonkey.ws/vncfb > > > > Ideally, we''d move qemu''s vnc support into a library to make it reusable. > > I had considered this. It''s a little awkward since b/c of the dependence > on QEMU''s async IO routines but it wouldn''t be that bad. > > At this point, it probably makes most sense to communicate the linear > offsets within the framebuffer that are dirty instead of computing a rect. > Since the QEMU VNC code already does rectangle finding and maintains > dirty tile bitmap, we don''t really have to attempt to find the rect in > the frontend at all.Well, I can only guess what you were thinking when you wrote the framebuffer code, but isn''t the current code merging updates to a single update at the configured framerate and aren''t you doing that to avoid flooding the ring? And if that''s the case, wouldn''t communicating the linear offsets have the same problems? We think that having a dirty bitmap as part of the frontend/backend protocol would be a good thing and are planning to use the same protocol with dirty bit scanning in the pagetables mapping the video ram of HVM guests. It would work like this: - have a page with two dirty bitmaps, each 64bit by 128 plus and indicator which bitmap is the active bitmap from the frontends point of view - [1] frontend records dirty information in the active bitmap - timer or external event causes backend to check if the indicator has changed - if not, then it either synchronously requests the frontend to switch bitmap or waits some more - backend then scans/clears the inactive bitmap - backend requests frontend to set a timer a few ms before the next time the backend wants to scan a bitmap - when the frontend''s timer fires, frontend switches bitmap and updates the indicator - go back to [1] This allows the backend to control the rate at which it wants to scan the bitmap without having to synchronously ask the frontend to flush the bitmap it is updating. We tile the screen in upto 64 vertical strips and upto 128 horizontal strips. We could move the indicator outside of this page and get finer grained updates. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2006-Jul-07 18:50 UTC
[Xen-devel] Re: Re: [PATCH 2/2] Virtual frame buffer: user space backend
On Fri, 07 Jul 2006 19:33:24 +0100, Christian Limpach wrote:> Well, I can only guess what you were thinking when you wrote the > framebuffer code, but isn''t the current code merging updates to a single > update at the configured framerate and aren''t you doing that to avoid > flooding the ring? And if that''s the case, wouldn''t communicating the > linear offsets have the same problems?It''s no so much flooding the ring, but what to do when the ring is full. The idea would be to push updates on the ring until it''s full, and then start storing the largest update. It''s just laziness to avoid buffering within the driver.> We think that having a dirty bitmap as part of the frontend/backend > protocol would be a good thing and are planning to use the same protocol > with dirty bit scanning in the pagetables mapping the video ram of HVM > guests.Actually, a shared dirty bitmap is exactly what I wanted to do for the next phase :-)> It would work like this: - have a page with two dirty bitmaps, > each 64bit by 128 plus and indicator which bitmap is the active bitmap > from the frontends point of view > - [1] frontend records dirty information in the active bitmap - timer or > external event causes backend to check if the indicator has changed - if > not, then it either synchronously requests the frontend to switch bitmap > or waits some more > - backend then scans/clears the inactive bitmap - backend requests > frontend to set a timer a few ms before the next time the backend wants to > scan a bitmap - when the frontend''s timer fires, frontend switches bitmap > and updates the indicatorSince the best we can do is page granularity (for now), why not just have a bitmap represent the dirty pages? Instead of switching bitmaps, why not just have the backend and frontend share a bitmap and do atomic get/sets on it? For instance, when the front-end timer goes off, it walks the dirty page list, and sets the bit of the corresponding page *after* calling zap_page_range and before releasing the lock. The back-end has it''s own timer (which may or may not be the same as the front-end). It walks through and does an atomic test-and-set to 0. With the QEMU VNC code, it would then mark all tiles that fall within this page. Those tiles happen to be 16x1 right now. Not requiring communication back and forth between the domains is pretty useful I think (especially if dom0 is on a different PCPU). Plus, I think the size of your tiling probably depends on however the backend is exposing things. Having tiles <= 16x16 is pretty useful for implementing Hextile in VNC for instance. We could even have the bitmap size be specified by the front-end. This way it could be set for 4k right now, but in the future, to something like 32 bytes. I think the key point is to have the bitmap represent linear regions of framebuffer memory instead of logical rectangles within the current resolution. Just some random thoughts.. Regards, Anthony Liguori> - go back to [1] > > This allows the backend to control the rate at which it wants to scan the > bitmap without having to synchronously ask the frontend to flush the > bitmap it is updating. > > We tile the screen in upto 64 vertical strips and upto 128 horizontal > strips. We could move the indicator outside of this page and get finer > grained updates. > > christian_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-07 22:50 UTC
Re: [Xen-devel] Re: Re: [PATCH 2/2] Virtual frame buffer: user space backend
On 7/7/06, Anthony Liguori <anthony@codemonkey.ws> wrote:> Since the best we can do is page granularity (for now), why not just have > a bitmap represent the dirty pages?Doesn''t your virtual framebuffer already support 2d operations? Also, the cirrus driver emulation in qemu already supports copyrect.> Instead of switching bitmaps, why not > just have the backend and frontend share a bitmap and do atomic get/sets > on it?Because we''d like to avoid atomic operations.> I think the key point is to have the bitmap represent linear regions of > framebuffer memory instead of logical rectangles within the current > resolution.Well, I don''t agree ;-) Because we want to transport 2D redraw information from the frontend to the backend. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2006-Jul-07 23:05 UTC
[Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On Fri, 07 Jul 2006 23:50:32 +0100, Christian Limpach wrote:> On 7/7/06, Anthony Liguori <anthony@codemonkey.ws> wrote: >> Since the best we can do is page granularity (for now), why not just >> have a bitmap represent the dirty pages? > > Doesn''t your virtual framebuffer already support 2d operations?Nope. X won''t even bother using the interface. Plus, serializing 2d ops is quite challenging when dealing with a shared buffer.> Also, the > cirrus driver emulation in qemu already supports copyrect.I know, I added support for it. It was really painful to get right too since the vga memory has to be flushed before the copyrect occurs (and the system has to disallow more writes until the copyrect completes). It''s going to be even more painful in Xen since the cost of that serialization is going to be greater.>> Instead of switching bitmaps, why not just have the backend and frontend >> share a bitmap and do atomic get/sets on it? > > Because we''d like to avoid atomic operations.Why? That seems odd to me.>> I think the key point is to have the bitmap represent linear regions of >> framebuffer memory instead of logical rectangles within the current >> resolution. > > Well, I don''t agree ;-) Because we want to transport 2D redraw > information from the frontend to the backend.So 2D information is very useful, especially for VNC. I think for Xen though, we may need to abandon the shared framebuffer completely and develop a lightweight framebuffer protocol. The idea would be to push the dirty''ing analysis to the frontend and have it communicate data over a higher bandwidth ring queue. This avoids having to deal with synchronizing the shared framebuffer for 2d ops. This is quite a bit different from the code today though. What do you think about getting rid of the shared framebuffer altogether? Regards, Anthony Liguori> christian_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Rik van Riel
2006-Jul-08 00:35 UTC
Re: [Xen-devel] Re: Re: [PATCH 2/2] Virtual frame buffer: user space backend
Christian Limpach wrote:> On 7/7/06, Anthony Liguori <anthony@codemonkey.ws> wrote:>> Instead of switching bitmaps, why not >> just have the backend and frontend share a bitmap and do atomic get/sets >> on it? > > Because we''d like to avoid atomic operations.Atomic should not be needed. Just synchronized access, ie. no unexpected behaviour and proper read/write smp barriers. -- "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-08 01:10 UTC
Re: [Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On 7/8/06, Anthony Liguori <anthony@codemonkey.ws> wrote:> On Fri, 07 Jul 2006 23:50:32 +0100, Christian Limpach wrote: > > Doesn''t your virtual framebuffer already support 2d operations? > > Nope. X won''t even bother using the interface. Plus, serializing 2d ops > is quite challenging when dealing with a shared buffer.That''s a shame.> > Also, the > > cirrus driver emulation in qemu already supports copyrect. > > I know, I added support for it. It was really painful to get right too > since the vga memory has to be flushed before the copyrect occurs (and the > system has to disallow more writes until the copyrect completes).Indeed, it was actually still a bit broken, relying on being able to send updates to the client even when the client hadn''t requested an update yet. Also the case where the source or destination rects are not within the client''s area is not really handled.> It''s going to be even more painful in Xen since the cost of that > serialization is going to be greater.We thought we could pass the copyrect information as a hint and then only vnc-copyrect the areas which are still intact.> >> Instead of switching bitmaps, why not just have the backend and frontend > >> share a bitmap and do atomic get/sets on it? > > > > Because we''d like to avoid atomic operations. > > Why? That seems odd to me.They''re expensive on SMP systems?> >> I think the key point is to have the bitmap represent linear regions of > >> framebuffer memory instead of logical rectangles within the current > >> resolution. > > > > Well, I don''t agree ;-) Because we want to transport 2D redraw > > information from the frontend to the backend. > > So 2D information is very useful, especially for VNC. I think for Xen > though, we may need to abandon the shared framebuffer completely and > develop a lightweight framebuffer protocol. > > The idea would be to push the dirty''ing analysis to the frontend and have > it communicate data over a higher bandwidth ring queue. This avoids > having to deal with synchronizing the shared framebuffer for 2d ops. > > This is quite a bit different from the code today though. > > What do you think about getting rid of the shared framebuffer altogether?Not sure, it could be an option. Might as well use VNC as the protocol then? christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-08 01:38 UTC
Re: [Xen-devel] Re: Re: [PATCH 2/2] Virtual frame buffer: user space backend
On 7/8/06, Rik van Riel <riel@redhat.com> wrote:> Christian Limpach wrote: > > On 7/7/06, Anthony Liguori <anthony@codemonkey.ws> wrote: > > >> Instead of switching bitmaps, why not > >> just have the backend and frontend share a bitmap and do atomic get/sets > >> on it? > > > > Because we''d like to avoid atomic operations. > > Atomic should not be needed. Just synchronized access, ie. > no unexpected behaviour and proper read/write smp barriers.You''re right and now I remember that we didn''t want the switching bitmaps because of atomic updates to it but because we need to publish the dirty bit information to the backend only after we''ve cleared the dirty bits in the pagetables mapping the framebuffer in fully virtualized guests, i.e.: - scan and clear the pagetable dirty bits and update the dirty bitmap - issue tlb flush across cpus - let the backend act on the dirty bitmap If we let the backend act on the dirty bitmap before we flush the tlb across cpus, another cpu can already dirty a page again before the tlb flush, the pagetable dirty bit doesn''t get set for that access and if the backend has already acted on the bit in the dirty bitmap, the update will get lost. By switching bitmaps, we avoid having to merge the bitmap we build in the first step above into a single shared bitmap. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2006-Jul-08 01:49 UTC
[Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On Sat, 08 Jul 2006 02:10:09 +0100, Christian Limpach wrote:>> I know, I added support for it. It was really painful to get right too >> since the vga memory has to be flushed before the copyrect occurs (and >> the system has to disallow more writes until the copyrect completes). > > Indeed, it was actually still a bit broken, relying on being able to send > updates to the client even when the client hadn''t requested an update yet. > Also the case where the source or destination rects are not within the > client''s area is not really handled.Actually, neither is really a problem. The VNC protocol does not specify which FramebufferUpdates correspond to which FramebufferUpdateRequests. There is a nasty race condition present in the VNC protocol related to this caused by SetPixelFormat.>> It''s going to be even more painful in Xen since the cost of that >> serialization is going to be greater. > > We thought we could pass the copyrect information as a hint and then only > vnc-copyrect the areas which are still intact.Yeah, I''m not convinced this will work all that well. The most common CopyRect is window dragging. For X, the whole window is moved at once. Under Windows, the window is broken into smaller rectangles and each are moved individually. Because CopyRects always come in groups, and tend to overlap, things get pretty nasty quickly. Plus, Windows tends to redraw the border of a Window when it moves so depending on when you check, things can be way off. That''s not to say that it won''t work for some cases. A framebuffer protocol is just a whole lot more deterministic.>> >> Instead of switching bitmaps, why not just have the backend and >> >> frontend share a bitmap and do atomic get/sets on it? >> > >> > Because we''d like to avoid atomic operations. >> >> Why? That seems odd to me. > > They''re expensive on SMP systems?Are they that expensive compared to what else is going on here? We''re talking about updates that occur at rather coarse granularities (10-15 times a second). Seems like the cost wouldn''t make much of a difference.> Not sure, it could be an option. Might as well use VNC as the protocol > then?Perhaps. VNC is a little rough around the edges (things like the SetPixelFormat race are a real pain). Would be nice to have something that supported more advanced features though like YUV overlays. Regards, Anthony Liguori> christian_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-08 10:20 UTC
Re: [Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
On 7/8/06, Anthony Liguori <anthony@codemonkey.ws> wrote:> On Sat, 08 Jul 2006 02:10:09 +0100, Christian Limpach wrote: > > >> I know, I added support for it. It was really painful to get right too > >> since the vga memory has to be flushed before the copyrect occurs (and > >> the system has to disallow more writes until the copyrect completes). > > > > Indeed, it was actually still a bit broken, relying on being able to send > > updates to the client even when the client hadn''t requested an update yet. > > Also the case where the source or destination rects are not within the > > client''s area is not really handled. > > Actually, neither is really a problem. The VNC protocol does not specify > which FramebufferUpdates correspond to which FramebufferUpdateRequests. > There is a nasty race condition present in the VNC protocol related to > this caused by SetPixelFormat.Actually they are: - the first one defeats the VNC protocol which is supposed to be client driven. If for example the client''s windows is minimized, it will no longer send update requests but your implementation keeps flooding the client with updates it doesn''t want or need. - you can''t really expect copy rect with the source rect outside of the area which is being sent to client to work. You get away with both at the cost of constantly updating a client with updates, including updates outside of the area it has requested but it doesn''t work so well if you have 10 domains where the user has minimized all but one window...> >> It''s going to be even more painful in Xen since the cost of that > >> serialization is going to be greater. > > > > We thought we could pass the copyrect information as a hint and then only > > vnc-copyrect the areas which are still intact. > > Yeah, I''m not convinced this will work all that well. The most common > CopyRect is window dragging. For X, the whole window is moved at once. > Under Windows, the window is broken into smaller rectangles and each are > moved individually. Because CopyRects always come in groups, and tend to > overlap, things get pretty nasty quickly. Plus, Windows tends to redraw > the border of a Window when it moves so depending on when you check, > things can be way off.We would merge the group of copyrects by computing the source and destination rects for the group of copyrects and then comparing the source on the clients framebuffer with the destination in the updated framebuffer. I wouldn''t be surprised if it made the Windows experience smoother.> >> >> Instead of switching bitmaps, why not just have the backend and > >> >> frontend share a bitmap and do atomic get/sets on it? > >> > > >> > Because we''d like to avoid atomic operations. > >> > >> Why? That seems odd to me. > > > > They''re expensive on SMP systems? > > Are they that expensive compared to what else is going on here? We''re > talking about updates that occur at rather coarse granularities (10-15 > times a second). Seems like the cost wouldn''t make much of a difference.Yeah, see my reply to Rik.> > Not sure, it could be an option. Might as well use VNC as the protocol > > then? > > Perhaps. VNC is a little rough around the edges (things like the > SetPixelFormat race are a real pain). Would be nice to have something > that supported more advanced features though like YUV overlays.The VNC protocol seems extensible enough. In any case, talk is cheap ;-) christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-10 07:37 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
"Christian Limpach" <christian.limpach@gmail.com> writes:> On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: >> Derived from >> http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle >> >> Converted to Xenstore and ported to current kernels. > > This looks good. > > Could you address the following issues: > > - the patch which defined struct xenfb_page seems to be missingD''oh!> - handling of the ring indexes: > + we generally prefer to store ring indexes in their unmasked form, > it makes debugging easier and it allows the ring to be used to its > full capacity instead of requiring leaving one slot empty to be able > distinguish empty/fullUnderstood.> + unless I misread the code, the producer (for frontend to backend > messages) seems to write to out_prod + 1 > out_cons, then increment > out_prob (xenfb_do_update) and then the consumer processes entries > from out_cons upto but not include the updated out_prod > (xenfb_on_fb_event) -- the producer for the other way around (backend > to frontend, xenfb_fb_event) seems to be correcter.I''ll look into this.> + the lack of barriers -- /* FIXME barriers */ doesn''t really cut it ;-) > ==> I would suggest looking at the block or net frontend/backend > drivers and copy/pasting some code from there...Will do.> - xenbus transactions can fail and there''s no code to retry failed transactionsWill do.> Additionally, I think that the dirty region protocol doesn''t really > perform too well in quite simple usage cases like having video play in > one corner of the screen and the mouse being moved in the opposite > corner. It''s probably good enough for this version and supporting > this protocol in the future isn''t too bad.There''s been some discussion on this. I''m not sure what bottom line emerged, if any. Do we have to improve this before it can be merged? Or before it can be declared stable? Or just eventually? Unless it''s the latter: do we already know in which direction to go? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-10 07:37 UTC
Re: [Xen-devel] [PATCH 2/2] Virtual frame buffer: user space backend
"Christian Limpach" <christian.limpach@gmail.com> writes:> On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: >> Straightforward conversion to Xenstore. >> >> Applies to hg repository at http://hg.codemonkey.ws/vncfb > > This also looks ok, two of the frontend issues apply here as well: > - handling of the ring indexes (masking of indexes and use of barriers) > - xenbus transactions can fail and there''s no code to retry failed transactions > > Additionally, it would be good to use the vnc server code which we''re > going to use in the updated ioemu. Sharing code for the framebuffers > for pv and non-pv domains is good and we don''t want the dependency on > libvncserver anymore and the qemu vnc code is much compacter. You''ll > want to grab the vnc files which come with qemu 0.8.1 > (http://xenbits.xensource.com/chris/ioemu-cvs-qemu-0.8.1.tar.bz2) and > then apply the following two patches: > http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=18f45f0721d8;file=vnc-cleanup;style=raw > http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=bc42f3c29c74;file=vnc-fixes;style=raw > > Ideally, we''d move qemu''s vnc support into a library to make it reusable.I''ll look into this. Thanks for your review! _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-10 10:57 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
On 7/10/06, Markus Armbruster <armbru@redhat.com> wrote:> > Additionally, I think that the dirty region protocol doesn''t really > > perform too well in quite simple usage cases like having video play in > > one corner of the screen and the mouse being moved in the opposite > > corner. It''s probably good enough for this version and supporting > > this protocol in the future isn''t too bad. > > There''s been some discussion on this. I''m not sure what bottom line > emerged, if any. Do we have to improve this before it can be merged? > Or before it can be declared stable? Or just eventually? Unless it''s > the latter: do we already know in which direction to go?I think the current stuff is good enough and the current protocol is not hard to support even if we have something better in the future, i.e. a guest using the current protocol is easy to support in a backend which also supports smarter ways of passing dirty region information. Thank you for working on this! christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-10 18:29 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
"Christian Limpach" <christian.limpach@gmail.com> writes:> On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: >> Derived from >> http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle >> >> Converted to Xenstore and ported to current kernels. > > This looks good. > > Could you address the following issues: > > - the patch which defined struct xenfb_page seems to be missingThis time it''s included.> - handling of the ring indexes: > + we generally prefer to store ring indexes in their unmasked form, > it makes debugging easier and it allows the ring to be used to its > full capacity instead of requiring leaving one slot empty to be able > distinguish empty/fullDone.> + unless I misread the code, the producer (for frontend to backend > messages) seems to write to out_prod + 1 > out_cons, then increment > out_prob (xenfb_do_update) and then the consumer processes entries > from out_cons upto but not include the updated out_prod > (xenfb_on_fb_event) -- the producer for the other way around (backend > to frontend, xenfb_fb_event) seems to be correcter.The old code confused me. I guess my ring index change takes care of this one, too.> + the lack of barriers -- /* FIXME barriers */ doesn''t really cut it ;-) > ==> I would suggest looking at the block or net frontend/backend > drivers and copy/pasting some code from there...Found only read barriers in block fe/be. console has read and write barriers. Now I''m confused. I added read barriers and documented my confusion.> - xenbus transactions can fail and there''s no code to retry failed transactionsDone.> Additionally, I think that the dirty region protocol doesn''t really > perform too well in quite simple usage cases like having video play in > one corner of the screen and the mouse being moved in the opposite > corner. It''s probably good enough for this version and supporting > this protocol in the future isn''t too bad.Saved for later.> I''m looking forward to seeing a new version of this patch, thanks! > > christianHere you go :) diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c --- a/arch/i386/kernel/setup-xen.c Fri Jun 16 19:34:13 2006 +0200 +++ b/arch/i386/kernel/setup-xen.c Mon Jul 10 20:18:50 2006 +0200 @@ -1787,8 +1787,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 d8434a6fdd05 drivers/xen/Kconfig --- a/drivers/xen/Kconfig Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Kconfig Mon Jul 10 20:18:50 2006 +0200 @@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP to a character device, allowing device prototyping in application space. Odds are that you want to say N 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 d8434a6fdd05 drivers/xen/Makefile --- a/drivers/xen/Makefile Fri Jun 16 19:34:13 2006 +0200 +++ b/drivers/xen/Makefile Mon Jul 10 20:18:50 2006 +0200 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP) += blkt obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/Makefile Mon Jul 10 20:18:50 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenfb/xenfb.c Mon Jul 10 20:18:50 2006 +0200 @@ -0,0 +1,565 @@ +/* + * 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; + xenbus_transaction_t 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->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; + + 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 d8434a6fdd05 drivers/xen/xenkbd/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/Makefile Mon Jul 10 20:18:50 2006 +0200 @@ -0,0 +1,1 @@ +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/xen/xenkbd/xenkbd.c Mon Jul 10 20:18:50 2006 +0200 @@ -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; + xenbus_transaction_t 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 d8434a6fdd05 include/linux/xenfb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/linux/xenfb.h Mon Jul 10 20:18:50 2006 +0200 @@ -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 d8434a6fdd05 include/linux/xenkbd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/linux/xenkbd.h Mon Jul 10 20:18:50 2006 +0200 @@ -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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-10 18:29 UTC
Re: [Xen-devel] [PATCH 2/2] Virtual frame buffer: user space backend
"Christian Limpach" <christian.limpach@gmail.com> writes:> On 6/26/06, Markus Armbruster <armbru@redhat.com> wrote: >> Straightforward conversion to Xenstore. >> >> Applies to hg repository at http://hg.codemonkey.ws/vncfb > > This also looks ok, two of the frontend issues apply here as well: > - handling of the ring indexes (masking of indexes and use of barriers) > - xenbus transactions can fail and there''s no code to retry failed transactionsBoth done. Same barrier confusion as for front end.> Additionally, it would be good to use the vnc server code which we''re > going to use in the updated ioemu. Sharing code for the framebuffers > for pv and non-pv domains is good and we don''t want the dependency on > libvncserver anymore and the qemu vnc code is much compacter. You''ll > want to grab the vnc files which come with qemu 0.8.1 > (http://xenbits.xensource.com/chris/ioemu-cvs-qemu-0.8.1.tar.bz2) and > then apply the following two patches: > http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=18f45f0721d8;file=vnc-cleanup;style=raw > http://xenbits.xensource.com/chris/xs-tools-ioemu.pq.hg?f=bc42f3c29c74;file=vnc-fixes;style=raw > > Ideally, we''d move qemu''s vnc support into a library to make it reusable. > > christianDownloaded it, patches applied with liberal fuzz, configure warned about gcc 4 issues, and gcc 4 promptly choked. I''ll dig deeper as soon as I find the time. diff -r f67e0a168879 Makefile --- a/Makefile Tue Jan 24 16:14:00 2006 -0500 +++ b/Makefile Mon Jul 10 20:18:57 2006 +0200 @@ -2,7 +2,7 @@ CFLAGS += -g -Wall ifneq ($(XENDIR),) CFLAGS += -I$(XENDIR)/tools/libxc -I$(XENDIR)/linux-2.6.12-xenU/include -LDFLAGS += -L$(XENDIR)/tools/libxc +LDFLAGS += -L$(XENDIR)/tools/libxc -L$(XENDIR)/tools/xenstore endif all: vncfb sdlfb @@ -13,7 +13,7 @@ sdlfb: sdlfb.o xenfb.o sdlfb: sdlfb.o xenfb.o sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore clean: $(RM) *.o *~ vncfb @@ -22,4 +22,4 @@ keymapping.o: CFLAGS += $(shell pkg-conf vncfb: vncfb.o xenfb.o keymapping.o vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore diff -r f67e0a168879 vncfb.c --- a/vncfb.c Tue Jan 24 16:14:00 2006 -0500 +++ b/vncfb.c Mon Jul 10 20:18:57 2006 +0200 @@ -39,7 +39,12 @@ static void on_ptr_event(int buttonMask, last_y = y; } +#if 0 #define BUG() do { printf("%d\n", __LINE__); return 1; } while(0) +#else +extern void abort(); +#define BUG() abort(); +#endif static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h) { diff -r f67e0a168879 xenfb.c --- a/xenfb.c Tue Jan 24 16:14:00 2006 -0500 +++ b/xenfb.c Mon Jul 10 20:18:57 2006 +0200 @@ -16,6 +16,7 @@ #include <stdio.h> #include <string.h> #include <time.h> +#include <xs.h> #include "xenfb.h" @@ -100,53 +101,80 @@ void xenfb_delete(struct xenfb *xenfb_pu static int xenfb_fb_event(struct xenfb_private *xenfb, union xenfb_in_event *event) { - uint32_t cons, prod; + uint32_t prod; struct xenfb_page *info = xenfb->fb_info; - - cons = XENFB_MASK_RING(info->in_cons, info->in); - prod = XENFB_MASK_RING(info->in_prod, info->in); - - if (XENFB_MASK_RING(prod + 1, info->in) != cons) { - struct ioctl_evtchn_notify notify; - - memcpy(&info->in[prod], event, sizeof(*event)); - info->in_prod = XENFB_MASK_RING(prod + 1, info->in); - notify.port = xenfb->fbdev_port; - return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify); - } - - errno = EAGAIN; - return -1; + struct ioctl_evtchn_notify notify; + + prod = info->in_prod; + if (prod - info->in_cons == XENFB_RING_SIZE(info->in)) { + errno = EAGAIN; + return -1; + } + + XENFB_RING_REF(info->in, prod) = *event; + info->in_prod = prod + 1; + notify.port = xenfb->fbdev_port; + return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify); } static int xenfb_kbd_event(struct xenfb_private *xenfb, union xenkbd_in_event *event) { - uint32_t cons, prod; + uint32_t prod; struct xenkbd_info *info = xenfb->kbd_info; - - cons = XENKBD_MASK_RING(info->in_cons, info->in); - prod = XENKBD_MASK_RING(info->in_prod, info->in); - - if (XENKBD_MASK_RING(prod + 1, info->in) != cons) { - struct ioctl_evtchn_notify notify; - - memcpy(&info->in[prod], event, sizeof(*event)); - info->in_prod = XENKBD_MASK_RING(prod + 1, info->in); - notify.port = xenfb->kbd_port; - return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify); - } - - errno = EAGAIN; - return -1; + struct ioctl_evtchn_notify notify; + + prod = info->in_prod; + if (prod - info->in_cons == XENKBD_RING_SIZE(info->in)) { + errno = EAGAIN; + return -1; + } + + XENKBD_RING_REF(info->in, prod) = *event; + info->in_prod = prod + 1; + notify.port = xenfb->kbd_port; + return ioctl(xenfb->fd, IOCTL_EVTCHN_NOTIFY, ¬ify); +} + +static char *xenfb_path_in_dom(struct xs_handle *h, + unsigned domid, const char *path, + char *buffer, size_t size) +{ + char *domp = xs_get_domain_path(h, domid); + int n = snprintf(buffer, size, "%s/%s", domp, path); + free(domp); + if (n >= size) + return NULL; + return buffer; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid, + const char *path, const char *fmt, + void *dest) +{ + char buffer[1024]; + char *p; + int ret; + + p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer)); + p = xs_read(xsh, XBT_NULL, p, NULL); + if (!p) + return -ENOENT; + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) + return -EDOM; + return 0; } bool xenfb_set_domid(struct xenfb *xenfb_pub, int domid) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; char buffer[1024]; - FILE *f; + struct xs_handle *xsh; + unsigned dummy; + int ret; + char *p, **vec; struct ioctl_evtchn_bind_interdomain bind; - time_t timeout; if (xenfb->domid != -1) { xenfb_unset_domid(xenfb); @@ -154,47 +182,53 @@ bool xenfb_set_domid(struct xenfb *xenfb return true; } - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.mfn", domid); - timeout = time(0); - do { - f = fopen(buffer, "r"); - if (!f) { - struct timeval tv = { 0, 500 }; - select(0, NULL, NULL, NULL, &tv); - } - } while (f == NULL && (timeout + 10) > time(0)); - - if (!f || fscanf(f, "%lu", &xenfb->fbdev_mfn) != 1) + xsh = xs_daemon_open_readonly(); + if (!xsh) + goto error; + + p = xenfb_path_in_dom(xsh, domid, "vfb", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenfb/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->fbdev_evtchn) != 1) + p = xenfb_path_in_dom(xsh, domid, "vkbd", buffer, sizeof(buffer)); + if (!xs_watch(xsh, p, "")) goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.mfn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%lu", &xenfb->kbd_mfn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); - - snprintf(buffer, sizeof(buffer), "/var/run/xenkbd/%d.evtchn", domid); - f = fopen(buffer, "r"); - if (!f || fscanf(f, "%d", &xenfb->kbd_evtchn) != 1) - goto error; - fclose(f); f = NULL; - - printf("%d\n", __LINE__); + + for (;;) { + ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu", + &xenfb->fbdev_mfn); + if (ret == -ENOENT || ret == -EAGAIN) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vfb/event-channel", "%u", + &xenfb->fbdev_evtchn); + if (ret == -ENOENT || ret == -EAGAIN) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/page-ref", "%lu", + &xenfb->kbd_mfn); + if (ret == -ENOENT || ret == -EAGAIN) + goto wait; + if (ret < 0) + goto error; + ret = xenfb_xs_scanf1(xsh, domid, "vkbd/event-channel", "%u", + &xenfb->kbd_evtchn); + if (ret == -ENOENT || ret == -EAGAIN) + goto wait; + if (ret < 0) + goto error; + break; + + wait: + printf("Waiting...\n"); + vec = xs_read_watch(xsh, &dummy); + if (!vec) + goto error; + free(vec); + } + xs_daemon_close(xsh); + xsh = NULL; printf("%d, %d, %d\n", xenfb->fd, xenfb->fbdev_evtchn, domid); @@ -312,9 +346,9 @@ bool xenfb_set_domid(struct xenfb *xenfb } error: printf("%d\n", __LINE__); - if (f) { - int serrno = errno; - fclose(f); + if (xsh) { + int serrno = errno; + xs_daemon_close(xsh); errno = serrno; } @@ -332,11 +366,10 @@ static void xenfb_on_fb_event(struct xen uint32_t prod, cons; struct xenfb_page *info = xenfb->fb_info; - prod = XENFB_MASK_RING(info->out_prod, info->out); - cons = XENFB_MASK_RING(info->out_cons, info->out); - - for (; cons != prod; cons = XENFB_MASK_RING(cons + 1, info->out)) { - union xenfb_out_event *event = &info->out[cons]; + prod = info->out_prod; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = info->out_cons; cons != prod; cons++) { + union xenfb_out_event *event = &XENFB_RING_REF(info->out, cons); switch (event->type) { case XENFB_TYPE_UPDATE: @@ -344,7 +377,7 @@ static void xenfb_on_fb_event(struct xen break; } } - + /* FIXME do I need a wmb() here? */ info->out_cons = cons; } @@ -353,18 +386,17 @@ static void xenfb_on_kbd_event(struct xe uint32_t prod, cons; struct xenkbd_info *info = xenfb->kbd_info; - prod = XENKBD_MASK_RING(info->out_prod, info->out); - cons = XENKBD_MASK_RING(info->out_cons, info->out); - - for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->out)) { - union xenkbd_out_event *event = &info->out[cons]; + prod = info->out_prod; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = info->out_cons; cons != prod; cons++) { + union xenkbd_out_event *event = &XENKBD_RING_REF(info->out, cons); switch (event->type) { default: break; } } - + /* FIXME do I need a wmb() here? */ info->out_cons = cons; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Jul-26 20:28 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
On 7/10/06, Markus Armbruster <armbru@redhat.com> wrote:> "Christian Limpach" <christian.limpach@gmail.com> writes: > > I''m looking forward to seeing a new version of this patch, thanks! > > Here you go :)Thanks and sorry for being a bit late getting back to you -- didn''t get around to it before leaving for OLS. I''ve tried the patches now and I seem to not get very far with them applied :-( - once I build a kernel with CONFIG_FB and CONFIG_XEN_FRAMEBUFFER enabled, I don''t seem to get any output on the xen text console anymore. I''ve tried quite a few combinations of xencons and console on the command line but didn''t find one that worked. - running vncfb and connecting a viewer works and I get the console output, but the kernel seems to get stuck as soon as it does any kind of busy waiting -- I obeserved this while the 5 second tls banner was printed (it never got to 4, eventualy softlockup kicks in) and after I moved /lib/tls out of the way, it got stuck in a similar way when setting the hardware clock (doesn''t make sense in domU, but should get the machine stuck either -- works without the framebuffer changes applied). This is all running debian in the domU. Do you have any recommendations how to get to a working setup and can you look into these issues? I''m also attaching two patches: - vfb-xenbus-transaction.diff: change xenbus_transaction_t to its non-typedef''ed form since the typedef''ed form doesn''t exist anymore. - vncfb-makefile-changes.diff: change the vncfb Makefile such that it works like other tools Makefiles. We''ll also need integration with xend before this is really useful, at least a way to start vncfb (should be similar to how we start qemu for hvm guests) and support for starting a vncviewer from vncfb would be nice (see tools/ioemu/patches/vnc-start-vncviewer). christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Jul-27 05:11 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
"Christian Limpach" <christian.limpach@gmail.com> writes:> On 7/10/06, Markus Armbruster <armbru@redhat.com> wrote: >> "Christian Limpach" <christian.limpach@gmail.com> writes: >> > I''m looking forward to seeing a new version of this patch, thanks! >> >> Here you go :) > > Thanks and sorry for being a bit late getting back to you -- didn''t > get around to it before leaving for OLS.No problem, as I figured you''d just be a bit delayed by OLS.> I''ve tried the patches now and I seem to not get very far with them applied :-( > > - once I build a kernel with CONFIG_FB and CONFIG_XEN_FRAMEBUFFER > enabled, I don''t seem to get any output on the xen text console > anymore. I''ve tried quite a few combinations of xencons and console > on the command line but didn''t find one that worked.Same here. The framebuffer takes over the console. There might be a way to avoid that, but I haven''t been able to figure it out.> - running vncfb and connecting a viewer works and I get the console > output, but the kernel seems to get stuck as soon as it does any kind > of busy waiting -- I obeserved this while the 5 second tls banner was > printed (it never got to 4, eventualy softlockup kicks in) and after I > moved /lib/tls out of the way, it got stuck in a similar way when > setting the hardware clock (doesn''t make sense in domU, but should get > the machine stuck either -- works without the framebuffer changes > applied). This is all running debian in the domU.I never saw such lockups. And I''m sure I got the annoying TLS banner. Which by the way isn''t about /lib/tls, it''s about how stuff was compiled. The offending instructions can be anywhere, and actually *are* in a few other places. I''ll see what I can do about the text console.> Do you have any recommendations how to get to a working setup and can > you look into these issues?If I can reproduce the lockup, I can probably fix it. I''ll update my hypervisor and kernels, and if it still works, I''ll install a Debian domU. Did you use stable, testing or unstable?> I''m also attaching two patches: > - vfb-xenbus-transaction.diff: change xenbus_transaction_t to its > non-typedef''ed form since the typedef''ed form doesn''t exist anymore. > - vncfb-makefile-changes.diff: change the vncfb Makefile such that it > works like other tools Makefiles.Thanks!> We''ll also need integration with xend before this is really useful, at > least a way to start vncfb (should be similar to how we start qemu for > hvm guests) and support for starting a vncviewer from vncfb would be > nice (see tools/ioemu/patches/vnc-start-vncviewer).Yes. One step at a time :) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Gerd Hoffmann
2006-Jul-27 07:26 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
>> - once I build a kernel with CONFIG_FB and CONFIG_XEN_FRAMEBUFFER >> enabled, I don''t seem to get any output on the xen text console >> anymore. I''ve tried quite a few combinations of xencons and console >> on the command line but didn''t find one that worked. > > Same here. The framebuffer takes over the console. There might be a > way to avoid that, but I haven''t been able to figure it out.No, there isn''t. xenlinux has hijacked major 4 from the vt subsystem for the xenconsole. IMHO that was a bad idea in the first place. UML made the same mistake btw. Now we have the situation that you can have either the framebuffer + vt or xenconsole, never both. Asking xenconsole to grab the serial line instead should work (xencons=ttyS). cheers, Gerd -- Gerd Hoffmann <kraxel@suse.de> http://www.suse.de/~kraxel/julika-dora.jpeg _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Laurent Vivier
2006-Jul-28 13:52 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
Hi, my domain hangs when I load xenfb module. The sequence is: dom0# sdlfb <id> ... domU# modprobe fbcon domU# modprobe xenkbd domU# modprobe xenfb ... HANGS HERE .... I found that it hangs in xenfb_event_handler() because info->page->in_prod and info->page->in_cons are not initialized correctly. I propose following correction: 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-07-28 12:58:47.000000000 +0200 +++ xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c 2006-07-28 15:28:23.000000000 +0200 @@ -414,6 +414,8 @@ 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); Regards, Laurent Markus Armbruster wrote:> Derived from > http://www.cs.utexas.edu/users/aliguori/vfb-20060124.bundle > > Converted to Xenstore and ported to current kernels. > > Signed-off-by: Markus Armbruster <armbru@redhat.com> > > > diff -r d8434a6fdd05 arch/i386/kernel/setup-xen.c > --- a/arch/i386/kernel/setup-xen.c Fri Jun 16 19:34:13 2006 +0200 > +++ b/arch/i386/kernel/setup-xen.c Fri Jun 23 10:07:51 2006 +0200 > @@ -1787,8 +1787,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 d8434a6fdd05 drivers/xen/Kconfig > --- a/drivers/xen/Kconfig Fri Jun 16 19:34:13 2006 +0200 > +++ b/drivers/xen/Kconfig Fri Jun 23 10:07:51 2006 +0200 > @@ -173,6 +173,29 @@ config XEN_BLKDEV_TAP > to a character device, allowing device prototyping in application > space. Odds are that you want to say N 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 d8434a6fdd05 drivers/xen/Makefile > --- a/drivers/xen/Makefile Fri Jun 16 19:34:13 2006 +0200 > +++ b/drivers/xen/Makefile Fri Jun 23 10:07:51 2006 +0200 > @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_TAP) += blkt > obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ > obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ > obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ > +obj-$(CONFIG_XEN_FRAMEBUFFER) += xenfb/ > +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd/ > diff -r d8434a6fdd05 drivers/xen/xenfb/Makefile > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/drivers/xen/xenfb/Makefile Fri Jun 23 10:07:51 2006 +0200 > @@ -0,0 +1,1 @@ > +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o > diff -r d8434a6fdd05 drivers/xen/xenfb/xenfb.c > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/drivers/xen/xenfb/xenfb.c Fri Jun 23 10:07:51 2006 +0200 > @@ -0,0 +1,579 @@ > +/* > + * 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 cons, prod; > + > + event.type = XENFB_TYPE_UPDATE; > + event.update.x = x; > + event.update.y = y; > + event.update.width = w; > + event.update.height = h; > + > + /* FIXME barriers */ > + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); > + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); > + prod = XENFB_MASK_RING(prod + 1, info->page->out); > + > + if (prod == cons) > + return; > + > + memcpy(&info->page->out[prod], &event, sizeof(event)); > + info->page->out_prod = prod; > + > + notify_remote_via_evtchn(info->evtchn); > +} > + > +static int xenfb_queue_full(struct xenfb_info *info) > +{ > + __u32 cons, prod; > + > + prod = XENFB_MASK_RING(info->page->out_prod, info->page->out); > + cons = XENFB_MASK_RING(info->page->out_cons, info->page->out); > + prod = XENFB_MASK_RING(prod + 1, info->page->out); > + > + return (prod == cons); > +} > + > +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; > + > + /* FIXME barriers */ > + prod = XENFB_MASK_RING(info->page->in_prod, info->page->in); > + cons = XENFB_MASK_RING(info->page->in_cons, info->page->in); > + > + if (prod == cons) > + return IRQ_HANDLED; > + > + for (; cons!=prod; cons = XENFB_MASK_RING(cons+1, info->page->in)) { > + union xenfb_in_event *event; > + event = &info->page->in[cons]; > + notify_remote_via_evtchn(info->evtchn); > + } > + > + 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; > + xenbus_transaction_t 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->width = 800; > + info->page->height = 600; > + info->page->depth = 32; // FIXME was 24; > + info->page->line_length = (info->page->depth / 8) * info->page->width; > + info->page->mem_length = xenfb_mem_len; > + > + 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; > + > + 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) > + 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; > + > +#if 0 > + xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn); > +#endif > + 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 0 > + if (xenfb_irq) > + unbind_from_irqhandler(xenfb_irq, NULL); > +#endif > + > +#if 0 > + 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); > +#endif > + 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 d8434a6fdd05 drivers/xen/xenkbd/Makefile > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/drivers/xen/xenkbd/Makefile Fri Jun 23 10:07:51 2006 +0200 > @@ -0,0 +1,1 @@ > +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o > diff -r d8434a6fdd05 drivers/xen/xenkbd/xenkbd.c > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > +++ b/drivers/xen/xenkbd/xenkbd.c Fri Jun 23 10:07:51 2006 +0200 > @@ -0,0 +1,206 @@ > +/* > + * 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; > + > + /* FIXME barriers */ > + prod = XENKBD_MASK_RING(info->in_prod, info->in); > + cons = XENKBD_MASK_RING(info->in_cons, info->in); > + > + if (prod == cons) > + return IRQ_HANDLED; > + > + for (; cons != prod; cons = XENKBD_MASK_RING(cons + 1, info->in)) { > + union xenkbd_in_event *event; > + > + event = &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); > + > + 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; > + xenbus_transaction_t 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 */ > + for (i = 0; i < 256; i++) > + set_bit(i, input_dev->keybit); > + > + input_dev->name = "Xen Virtual Keyboard/Mouse"; > + > + input_register_device(input_dev); > + > + 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) > + 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 > + 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"); > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel > >-- Laurent Vivier Bull, Architect of an Open World (TM) http://www.bullopensource.org/ext4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Laurent Vivier
2006-Jul-28 15:55 UTC
Re: [Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
Hi, sdlfb has some problems to correctly identify keys on my french keyboard. A use of SDL scancode instead of SDL symbol id corrects this problem. I propose following modification: --- sdlfb.c.org 2006-07-28 17:46:17.000000000 +0200 +++ sdlfb.c 2006-07-28 17:40:53.000000000 +0200 @@ -22,52 +22,111 @@ void sdl_update(struct xenfb *xenfb, int } int sdl2linux[1024] = { - [SDLK_a] = KEY_A, - [SDLK_b] = KEY_B, - [SDLK_c] = KEY_C, - [SDLK_d] = KEY_D, - [SDLK_e] = KEY_E, - [SDLK_f] = KEY_F, - [SDLK_g] = KEY_G, - [SDLK_h] = KEY_H, - [SDLK_i] = KEY_I, - [SDLK_j] = KEY_J, - [SDLK_k] = KEY_K, - [SDLK_l] = KEY_L, - [SDLK_m] = KEY_M, - [SDLK_n] = KEY_N, - [SDLK_o] = KEY_O, - [SDLK_p] = KEY_P, - [SDLK_q] = KEY_Q, - [SDLK_r] = KEY_R, - [SDLK_s] = KEY_S, - [SDLK_t] = KEY_T, - [SDLK_u] = KEY_U, - [SDLK_v] = KEY_V, - [SDLK_w] = KEY_W, - [SDLK_x] = KEY_X, - [SDLK_y] = KEY_Y, - [SDLK_z] = KEY_Z, - [SDLK_0] = KEY_0, - [SDLK_1] = KEY_1, - [SDLK_2] = KEY_2, - [SDLK_3] = KEY_3, - [SDLK_4] = KEY_4, - [SDLK_5] = KEY_5, - [SDLK_6] = KEY_6, - [SDLK_7] = KEY_7, - [SDLK_8] = KEY_8, - [SDLK_9] = KEY_9, - [SDLK_SPACE] = KEY_SPACE, - [SDLK_RETURN] = KEY_ENTER, - [SDLK_PERIOD] = KEY_DOT, - [SDLK_SLASH] = KEY_SLASH, - [SDLK_BACKSPACE] = KEY_BACKSPACE, - [SDLK_TAB] = KEY_TAB, - [SDLK_LSHIFT] = KEY_LEFTSHIFT, - [SDLK_RSHIFT] = KEY_RIGHTSHIFT, - [SDLK_LALT] = KEY_LEFTALT, - [SDLK_RALT] = KEY_RIGHTALT, + [9] = KEY_ESC, + [67] = KEY_F1, + [68] = KEY_F2, + [69] = KEY_F3, + [70] = KEY_F4, + [71] = KEY_F5, + [72] = KEY_F6, + [73] = KEY_F7, + [74] = KEY_F8, + [75] = KEY_F9, + [76] = KEY_F10, + [95] = KEY_F11, + [96] = KEY_F12, + [78] = KEY_SCROLLLOCK, + [49] = KEY_GRAVE, + [10] = KEY_1, + [11] = KEY_2, + [12] = KEY_3, + [13] = KEY_4, + [14] = KEY_5, + [15] = KEY_6, + [16] = KEY_7, + [17] = KEY_8, + [18] = KEY_9, + [19] = KEY_0, + [20] = KEY_MINUS, + [21] = KEY_EQUAL, + [22] = KEY_BACKSPACE, + [106] = KEY_INSERT, + [97] = KEY_HOME, + [99] = KEY_UP, + [77] = KEY_NUMLOCK, + [23] = KEY_TAB, + [24] = KEY_Q, + [25] = KEY_W, + [26] = KEY_E, + [27] = KEY_R, + [28] = KEY_T, + [29] = KEY_Y, + [30] = KEY_U, + [31] = KEY_I, + [32] = KEY_O, + [33] = KEY_P, + [34] = KEY_LEFTBRACE, + [35] = KEY_RIGHTBRACE, + [36] = KEY_ENTER, + [38] = KEY_A, + [39] = KEY_S, + [40] = KEY_D, + [41] = KEY_F, + [42] = KEY_G, + [43] = KEY_H, + [44] = KEY_J, + [45] = KEY_K, + [46] = KEY_L, + [47] = KEY_SEMICOLON, + [48] = KEY_APOSTROPHE, + [52] = KEY_Z, + [53] = KEY_X, + [54] = KEY_C, + [55] = KEY_V, + [56] = KEY_B, + [57] = KEY_N, + [58] = KEY_M, + [59] = KEY_COMMA, + [60] = KEY_DOT, + [61] = KEY_SLASH, + [62] = KEY_RIGHTSHIFT, + [51] = KEY_BACKSLASH, + [112] = KEY_KPSLASH, + [63] = KEY_KPASTERISK, + [82] = KEY_KPMINUS, + [110] = KEY_PAUSE, + [111] = KEY_BREAK, + [107] = KEY_DELETE, + [103] = KEY_END, + [105] = KEY_PAGEDOWN, + [79] = KEY_KP7, + [80] = KEY_KP8, + [81] = KEY_KP9, + [86] = KEY_KPPLUS, + [66] = KEY_CAPSLOCK, + [83] = KEY_KP4, + [84] = KEY_KP5, + [85] = KEY_KP6, + [50] = KEY_LEFTSHIFT, + [94] = KEY_COMPOSE, + [98] = KEY_UP, + [87] = KEY_KP1, + [88] = KEY_KP2, + [89] = KEY_KP3, + [108] = KEY_KPENTER, + [37] = KEY_LEFTCTRL, + [115] = KEY_LEFTMETA, + [64] = KEY_LEFTALT, + [65] = KEY_SPACE, + [113] = KEY_RIGHTALT, + [116] = KEY_RIGHTMETA, + //[117] Menu ? + [109] = KEY_RIGHTCTRL, + [100] = KEY_LEFT, + [104] = KEY_DOWN, + [102] = KEY_RIGHT, + [90] = KEY_KP0, + [91] = KEY_KPDOT, }; int main(int argc, char **argv) @@ -128,7 +187,7 @@ int main(int argc, char **argv) case SDL_KEYUP: xenfb_send_key(xenfb, event.type == SDL_KEYDOWN, - sdl2linux[event.key.keysym.sym]); + sdl2linux[event.key.keysym.scancode]); break; case SDL_MOUSEMOTION: { int x, y; Regards, Laurent -- Laurent Vivier Bull, Architect of an Open World (TM) http://www.bullopensource.org/ext4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Aug-04 07:54 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
Laurent Vivier <Laurent.Vivier@bull.net> writes:> Hi, > > my domain hangs when I load xenfb module. > > The sequence is: > dom0# sdlfb <id> > ... > domU# modprobe fbcon > domU# modprobe xenkbd > domU# modprobe xenfb > ... HANGS HERE .... > > I found that it hangs in xenfb_event_handler() because info->page->in_prod and > info->page->in_cons are not initialized correctly.You''re right. I missed that error, then had the bad luck that it happened to work for me every time.> I propose following correction: > > 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-07-28 12:58:47.000000000 +0200 > +++ xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c > 2006-07-28 15:28:23.000000000 +0200 > @@ -414,6 +414,8 @@ > 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;Works for me.> ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, > 0, "xenfb", info); > > > Regards, > LaurentSorry for the slow reply, I was sick. Thanks! _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Aug-04 07:57 UTC
Re: [Xen-devel] Re: [PATCH 2/2] Virtual frame buffer: user space backend
Laurent Vivier <Laurent.Vivier@bull.net> writes:> Hi, > > sdlfb has some problems to correctly identify keys on my french keyboard. > > A use of SDL scancode instead of SDL symbol id corrects this problem. > > I propose following modification:[...] I''m still too ignorant of SDL to judge whether this is the right thing to do. Advice, anybody? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2006-Aug-04 08:00 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
Regarding the lockups you saw: I still don''t get them, and there''s the uninitialized variable bug Laurent reported (with fix). Could you try whether that one takes care of your lockups as well? _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2006-Aug-04 08:34 UTC
Re: [Xen-devel] [PATCH 1/2] Virtual frame buffer: frontend
On 8/4/06, Markus Armbruster <armbru@redhat.com> wrote:> Regarding the lockups you saw: I still don''t get them, and there''s the > uninitialized variable bug Laurent reported (with fix). Could you try > whether that one takes care of your lockups as well?Yeah, that sounds like a likely cause for the lockups I was seeing. Will try it soon. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel