[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel][RFC]Dynamic modes support for PV xenfb (included)
Rehash following last round of comments What changed: 1. Reverted back to pd[] for mappings, removed all gntref code. 2. Added videoram vfb parameter so that admin can limit what a frontend can allocate 3. xenfb kernel parameters are used to set the built-in width and height to support configure less X11. extra="xenfb.video=5,1024,768 " Unless I missed something I think this addresses all of the raised concerns. Thanks to all that have looked at this never ending RFC and commented. Pat diff -r e32fe4703ab6 drivers/xen/fbfront/xenfb.c --- a/drivers/xen/fbfront/xenfb.c Tue Jan 29 11:53:33 2008 +0000 +++ b/drivers/xen/fbfront/xenfb.c Mon Feb 04 11:34:36 2008 -0700 @@ -28,6 +28,7 @@ #include <asm/hypervisor.h> #include <xen/evtchn.h> #include <xen/interface/io/fbif.h> +#include <xen/interface/io/kbdif.h> #include <xen/interface/io/protocols.h> #include <xen/xenbus.h> #include <linux/kthread.h> @@ -62,6 +63,13 @@ struct xenfb_info struct xenfb_page *page; unsigned long *mfns; int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + int feature_resize; /* Backend has resize feature */ + int resize_dpy; + int xres, yres; /* current resolution */ + int fb_size; /* fb size in bytes */ + int fb_width; /* fb mem width in pixels */ + int fb_height; /* fb mem height in pixels */ + int fb_stride; /* fb stride in bytes */ struct xenbus_device *xbdev; }; @@ -129,20 +137,48 @@ struct xenfb_info * * Oh well, we wont be updating the writes to this page anytime soon. */ +enum {KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT}; +static int video[KPARAM_CNT] = {0}; +static int video_cnt = 0; +module_param_array(video, int, &video_cnt, 0); +MODULE_PARM_DESC(video, + "Size of video memory in MB and width,height in pixels, default = (2,800,600)"); + +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#define MB_ (1024*1024) +#define XENFB_PIXCLOCK 9025 /* Xorg "1280x1024" 110.80 to FB 1000000/110.80 */ +#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8) static int xenfb_fps = 20; -static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; +static unsigned long xenfb_mem_len = 0; static int xenfb_remove(struct xenbus_device *); static void xenfb_init_shared_page(struct xenfb_info *); static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); static void xenfb_disconnect_backend(struct xenfb_info *); +static void xenfb_refresh(struct xenfb_info *info, int x1, int y1, int w, int h); + +static void xenfb_send_event(struct xenfb_info *info, + union xenfb_out_event *event) +{ + __u32 prod; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = *event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_irq(info->irq); +} 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; @@ -150,14 +186,19 @@ static void xenfb_do_update(struct xenfb event.update.width = w; event.update.height = h; - prod = info->page->out_prod; - /* caller ensures !xenfb_queue_full() */ - mb(); /* ensure ring space available */ - XENFB_OUT_RING_REF(info->page, prod) = event; - wmb(); /* ensure ring contents visible */ - info->page->out_prod = prod + 1; - - notify_remote_via_irq(info->irq); + xenfb_send_event(info, &event); +} + +static void xenfb_do_resize(struct xenfb_info *info) +{ + union xenfb_out_event event; + + event.type = XENFB_TYPE_RESIZE; + event.resize.width = info->xres; + event.resize.height = info->yres; + event.resize.stride = info->fb_stride; + + xenfb_send_event(info, &event); } static int xenfb_queue_full(struct xenfb_info *info) @@ -209,6 +250,16 @@ static void xenfb_update_screen(struct x xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); } +static void xenfb_resize_screen(struct xenfb_info *info) +{ + if (xenfb_queue_full(info)) + return; + + info->resize_dpy = 0; + xenfb_do_resize(info); + xenfb_refresh(info, 0, 0, info->xres, info->yres); +} + static int xenfb_thread(void *data) { struct xenfb_info *info = data; @@ -217,6 +268,9 @@ static int xenfb_thread(void *data) if (info->dirty) { info->dirty = 0; xenfb_update_screen(info); + } + if (info->resize_dpy) { + xenfb_resize_screen(info); } wait_event_interruptible(info->wq, kthread_should_stop() || info->dirty); @@ -413,6 +467,47 @@ static int xenfb_mmap(struct fb_info *fb return 0; } +static int +xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + + xenfb_info = info->par; + + if (!xenfb_info->feature_resize) { + if (var->xres == XENFB_WIDTH && var->yres == XENFB_HEIGHT + && var->bits_per_pixel == xenfb_info->page->depth) { + return 0; + } + return -EINVAL; + } + if (var->bits_per_pixel == xenfb_info->page->depth && + xenfb_info->fb_width >= var->xres && + xenfb_mem_len >= (var->xres * var->yres * (xenfb_info->page->depth / 8))) { + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + return 0; + } + return -EINVAL; +} + +static int xenfb_set_par(struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + + xenfb_info = info->par; + + if (xenfb_info->xres != info->var.xres || + xenfb_info->yres != info->var.yres) { + xenfb_info->resize_dpy = 1; + xenfb_info->xres = info->var.xres_virtual = info->var.xres; + xenfb_info->yres = info->var.yres_virtual = info->var.yres; + info->fix.line_length = xenfb_info->fb_stride; + xenkbd_set_ptr_geometry(xenfb_info->xres, xenfb_info->yres); + } + return 0; +} + static struct fb_ops xenfb_fb_ops = { .owner = THIS_MODULE, .fb_setcolreg = xenfb_setcolreg, @@ -420,6 +515,8 @@ static struct fb_ops xenfb_fb_ops = { .fb_copyarea = xenfb_copyarea, .fb_imageblit = xenfb_imageblit, .fb_mmap = xenfb_mmap, + .fb_check_var = xenfb_check_var, + .fb_set_par = xenfb_set_par, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id, @@ -450,6 +547,8 @@ static int __devinit xenfb_probe(struct { struct xenfb_info *info; struct fb_info *fb_info; + int fb_size; + int val; int ret; info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -457,6 +556,32 @@ static int __devinit xenfb_probe(struct xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; } + + info->fb_width = info->xres = XENFB_WIDTH; + info->fb_height = info->yres = XENFB_HEIGHT; + fb_size = XENFB_DEFAULT_FB_LEN; + + if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { + if (val * MB_ >= XENFB_DEFAULT_FB_LEN) { + video[KPARAM_MEM] = val; + fb_size = val * MB_; + } + } + + if (video_cnt == KPARAM_CNT && (video[KPARAM_MEM] * MB_) >= XENFB_DEFAULT_FB_LEN) { + fb_size = video[KPARAM_MEM] * MB_; + if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH/8 < fb_size) { + info->fb_width = info->xres = video[KPARAM_WIDTH]; + info->fb_height = info->yres = video[KPARAM_HEIGHT]; + } + } + + info->fb_size = fb_size; + info->fb_stride = info->fb_width * (XENFB_DEPTH / 8); + xenfb_mem_len = info->fb_size; + + xenkbd_set_ptr_geometry(info->fb_width, info->fb_height); + dev->dev.driver_data = info; info->xbdev = dev; info->irq = -1; @@ -504,9 +629,10 @@ static int __devinit xenfb_probe(struct fb_info->screen_base = info->fb; 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.xres_virtual = fb_info->var.xres = info->xres; + fb_info->var.yres_virtual = fb_info->var.yres = info->yres; fb_info->var.bits_per_pixel = info->page->depth; + fb_info->var.pixclock = XENFB_PIXCLOCK; fb_info->var.red = (struct fb_bitfield){16, 8, 0}; fb_info->var.green = (struct fb_bitfield){8, 8, 0}; @@ -572,6 +698,8 @@ static int xenfb_resume(struct xenbus_de xenfb_disconnect_backend(info); xenfb_init_shared_page(info); + if (info->xres != XENFB_WIDTH || info->yres != XENFB_HEIGHT) + info->resize_dpy = 1; return xenfb_connect_backend(dev, info); } @@ -600,6 +728,7 @@ static void xenfb_init_shared_page(struc static void xenfb_init_shared_page(struct xenfb_info *info) { int i; + int epd = PAGE_SIZE/sizeof(info->mfns[0]); for (i = 0; i < info->nr_pages; i++) info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); @@ -607,12 +736,13 @@ static void xenfb_init_shared_page(struc for (i = 0; i < info->nr_pages; i++) info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); - info->page->pd[0] = vmalloc_to_mfn(info->mfns); - info->page->pd[1] = 0; - info->page->width = XENFB_WIDTH; - info->page->height = XENFB_HEIGHT; + for (i = 0; i * epd < info->nr_pages; i++) + info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); + + info->page->width = info->xres; + info->page->height = info->yres; info->page->depth = XENFB_DEPTH; - info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->line_length = info->fb_stride; 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; @@ -710,6 +840,11 @@ static void xenfb_backend_changed(struct val = 0; if (val) info->update_wanted = 1; + + if (xenbus_scanf(XBT_NIL, dev->otherend, + "feature-resize", "%d", &val) < 0) + val = 0; + info->feature_resize = val; break; case XenbusStateClosing: diff -r e32fe4703ab6 drivers/xen/fbfront/xenkbd.c --- a/drivers/xen/fbfront/xenkbd.c Tue Jan 29 11:53:33 2008 +0000 +++ b/drivers/xen/fbfront/xenkbd.c Mon Feb 04 08:41:35 2008 -0700 @@ -40,6 +40,10 @@ static int xenkbd_remove(struct xenbus_d static int xenkbd_remove(struct xenbus_device *); static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); static void xenkbd_disconnect_backend(struct xenkbd_info *); + +static int max_abs_xres; +static int max_abs_yres; +static struct input_dev *mouse_ptr; /* * Note: if you need to send out events, see xenfb_do_update() for how @@ -163,8 +167,8 @@ int __devinit xenkbd_probe(struct xenbus for (i = BTN_LEFT; i <= BTN_TASK; i++) set_bit(i, ptr->keybit); ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + input_set_abs_params(ptr, ABS_X, 0, max_abs_xres, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, max_abs_yres, 0, 0); ret = input_register_device(ptr); if (ret) { @@ -172,7 +176,7 @@ int __devinit xenkbd_probe(struct xenbus xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); goto error; } - info->ptr = ptr; + mouse_ptr = info->ptr = ptr; ret = xenkbd_connect_backend(dev, info); if (ret < 0) @@ -338,6 +342,18 @@ static void __exit xenkbd_cleanup(void) return xenbus_unregister_driver(&xenkbd); } +void xenkbd_set_ptr_geometry(int xres, int yres) +{ + max_abs_xres = xres; + max_abs_yres = yres; + if (mouse_ptr) { + input_set_abs_params(mouse_ptr, ABS_X, 0, max_abs_xres, 0, 0); + input_set_abs_params(mouse_ptr, ABS_Y, 0, max_abs_yres, 0, 0); + input_event(mouse_ptr, EV_SYN, SYN_CONFIG, 0); + } +} +EXPORT_SYMBOL(xenkbd_set_ptr_geometry); + module_init(xenkbd_init); module_exit(xenkbd_cleanup); diff -r e32fe4703ab6 include/xen/interface/io/fbif.h --- a/include/xen/interface/io/fbif.h Tue Jan 29 11:53:33 2008 +0000 +++ b/include/xen/interface/io/fbif.h Mon Feb 04 08:53:20 2008 -0700 @@ -50,12 +50,28 @@ struct xenfb_update int32_t height; /* rect height */ }; +/* + * Framebuffer resize notification event + * Capable backend sets feature-resize in xenstore. + */ +#define XENFB_TYPE_RESIZE 3 + +struct xenfb_resize +{ + uint8_t type; /* XENFB_TYPE_RESIZE */ + int32_t width; /* width in pixels */ + int32_t height; /* height in pixels */ + int32_t stride; /* stride in bytes */ + int32_t depth; /* future */ +}; + #define XENFB_OUT_EVENT_SIZE 40 union xenfb_out_event { uint8_t type; struct xenfb_update update; + struct xenfb_resize resize; char pad[XENFB_OUT_EVENT_SIZE]; }; @@ -109,21 +125,13 @@ struct xenfb_page * Each directory page holds PAGE_SIZE / sizeof(*pd) * framebuffer pages, and can thus map up to PAGE_SIZE * * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory - * pages should be enough for a while. + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs + * 64 bit. 256 directories give enough room for a 512 Meg + * framebuffer with a max resolution of 12,800x10,240. Should + * be enough for a while with room leftover for expansion. */ - unsigned long pd[2]; + unsigned long pd[256]; }; - -/* - * Wart: xenkbd needs to know resolution. Put it here until a better - * solution is found, but don't leak it to the backend. - */ -#ifdef __KERNEL__ -#define XENFB_WIDTH 800 -#define XENFB_HEIGHT 600 -#define XENFB_DEPTH 32 -#endif #endif diff -r e32fe4703ab6 include/xen/interface/io/kbdif.h --- a/include/xen/interface/io/kbdif.h Tue Jan 29 11:53:33 2008 +0000 +++ b/include/xen/interface/io/kbdif.h Fri Feb 01 11:54:37 2008 -0700 @@ -119,6 +119,10 @@ struct xenkbd_page uint32_t out_cons, out_prod; }; +#ifdef __KERNEL__ +void xenkbd_set_ptr_geometry(int xres, int yres); +#endif + #endif /* diff -r 1b013d10c6d1 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Mon Jan 28 10:37:08 2008 +0000 +++ b/tools/ioemu/hw/xenfb.c Mon Feb 04 07:30:36 2008 -0700 @@ -264,6 +264,9 @@ struct xenfb *xenfb_new(int domid, Displ xenfb->ds = ds; xenfb_device_set_domain(&xenfb->fb, domid); xenfb_device_set_domain(&xenfb->kbd, domid); + + /* Indicate we have the frame buffer resize feature */ + xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1"); fprintf(stderr, "FB: Waiting for KBD backend creation\n"); xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd); @@ -510,6 +513,12 @@ static void xenfb_on_fb_event(struct xen } xenfb_guest_copy(xenfb, x, y, w, h); break; + case XENFB_TYPE_RESIZE: + xenfb->width = event->resize.width; + xenfb->height = event->resize.height; + xenfb->row_stride = event->resize.stride; + dpy_resize(xenfb->ds, xenfb->width, xenfb->height); + break; } } mb(); /* ensure we're done with ring contents */ @@ -672,6 +681,7 @@ static int xenfb_read_frontend_fb_config static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) { struct xenfb_page *fb_page; int val; + int videoram = 0; if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update", "%d", &val) < 0) @@ -686,14 +696,22 @@ static int xenfb_read_frontend_fb_config xenfb->protocol[0] = '\0'; xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1"); - /* TODO check for permitted ranges */ + if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.nodename, "videoram", "%d", &videoram) < 0) + videoram = 0; + videoram = videoram * 1024 * 1024; + fb_page = xenfb->fb.page; xenfb->depth = fb_page->depth; xenfb->width = fb_page->width; xenfb->height = fb_page->height; - /* TODO check for consistency with the above */ xenfb->fb_len = fb_page->mem_length; xenfb->row_stride = fb_page->line_length; + /* Protect against hostile frontend, limit fb_len to configured */ + if (videoram && xenfb->fb_len > videoram) { + xenfb->fb_len = videoram; + if (xenfb->row_stride * xenfb->height > xenfb->fb_len) + xenfb->height = xenfb->fb_len/xenfb->row_stride; + } fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n", fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length); if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0) diff -r 1b013d10c6d1 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Mon Jan 28 10:37:08 2008 +0000 +++ b/tools/python/xen/xend/server/vfbif.py Mon Feb 04 08:32:10 2008 -0700 @@ -6,7 +6,7 @@ import os import os CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused', - 'display', 'xauthority', 'keymap', + 'videoram', 'display', 'xauthority', 'keymap', 'uuid', 'location', 'protocol'] class VfbifController(DevController): diff -r 1b013d10c6d1 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Mon Jan 28 10:37:08 2008 +0000 +++ b/tools/python/xen/xm/create.py Mon Feb 04 09:19:41 2008 -0700 @@ -490,6 +490,10 @@ gopts.var('vncunused', val='', use="""Try to find an unused port for the VNC server. Only valid when vnc=1.""") +gopts.var('videoram', val='', + fn=set_value, default=None, + use="""Amount of videoram PV guest can allocate for frame buffer.""") + gopts.var('sdl', val='', fn=set_value, default=None, use="""Should the device model use SDL?""") @@ -620,7 +624,7 @@ def configure_vfbs(config_devs, vals): d['type'] = 'sdl' for (k,v) in d.iteritems(): if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display', - 'xauthority', 'type', 'vncpasswd' ]: + 'videoram', 'xauthority', 'type', 'vncpasswd' ]: err("configuration option %s unknown to vfbs" % k) config.append([k,v]) if not d.has_key("keymap"): diff -r 1b013d10c6d1 xen/include/public/io/fbif.h --- a/xen/include/public/io/fbif.h Mon Jan 28 10:37:08 2008 +0000 +++ b/xen/include/public/io/fbif.h Mon Feb 04 08:07:19 2008 -0700 @@ -50,12 +50,28 @@ struct xenfb_update int32_t height; /* rect height */ }; +/* + * Framebuffer resize notification event + * Capable backend sets feature-resize in xenstore. + */ +#define XENFB_TYPE_RESIZE 3 + +struct xenfb_resize +{ + uint8_t type; /* XENFB_TYPE_RESIZE */ + int32_t width; /* width in pixels */ + int32_t height; /* height in pixels */ + int32_t stride; /* stride in bytes */ + int32_t depth; /* future */ +}; + #define XENFB_OUT_EVENT_SIZE 40 union xenfb_out_event { uint8_t type; struct xenfb_update update; + struct xenfb_resize resize; char pad[XENFB_OUT_EVENT_SIZE]; }; @@ -109,21 +125,13 @@ struct xenfb_page * Each directory page holds PAGE_SIZE / sizeof(*pd) * framebuffer pages, and can thus map up to PAGE_SIZE * * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory - * pages should be enough for a while. + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs + * 64 bit. 256 directories give enough room for a 512 Meg + * framebuffer with a max resolution of 12,800x10,240. Should + * be enough for a while with room leftover for expansion. */ - unsigned long pd[2]; + unsigned long pd[256]; }; - -/* - * Wart: xenkbd needs to know resolution. Put it here until a better - * solution is found, but don't leak it to the backend. - */ -#ifdef __KERNEL__ -#define XENFB_WIDTH 800 -#define XENFB_HEIGHT 600 -#define XENFB_DEPTH 32 -#endif #endif diff -r 1b013d10c6d1 xen/include/public/io/kbdif.h --- a/xen/include/public/io/kbdif.h Mon Jan 28 10:37:08 2008 +0000 +++ b/xen/include/public/io/kbdif.h Fri Feb 01 07:59:20 2008 -0700 @@ -119,6 +119,10 @@ struct xenkbd_page uint32_t out_cons, out_prod; }; +#ifdef __KERNEL__ +void xenkbd_set_ptr_geometry(int xres, int yres); +#endif + #endif /* _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |