All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC]Dynamic modes support for PV xenfb (included)
@ 2008-02-04 18:49 Pat Campbell
  2008-02-05  9:52 ` Markus Armbruster
  0 siblings, 1 reply; 29+ messages in thread
From: Pat Campbell @ 2008-02-04 18:49 UTC (permalink / raw)
  To: Daniel P. Berrange, Markus Armbruster, xen-devel

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


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



[-- Attachment #2: xen-fbfront-resize.patch --]
[-- Type: text/x-patch, Size: 13174 bytes --]

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
 
 /*

[-- Attachment #3: xen-fbback-resize.patch --]
[-- Type: text/x-patch, Size: 6332 bytes --]

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
 
 /*

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

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

^ permalink raw reply	[flat|nested] 29+ messages in thread
* [RFC] Dynamic modes support for PV xenfb (included)
@ 2008-03-09 21:19 Pat Campbell
  2008-03-09 21:29 ` Samuel Thibault
                   ` (3 more replies)
  0 siblings, 4 replies; 29+ messages in thread
From: Pat Campbell @ 2008-03-09 21:19 UTC (permalink / raw)
  To: xen-devel, Markus Armbruster, Samuel Thibault, Daniel P. Berrange

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

Patches are against xen-unstable tip

What changed since last comment round. (No major structural
surprises this time:-).

 Backend:
  1. In the resize event handler 
       Disabled shared memory (Need to fix)
       Invalidate the buffer 
  2. Added videoram config variable to limit hostile front 
     end frame buffer memory size.  
  3. Sets feature-resize and width/height in xenstore 
     before frontend connected. width/height are for xenkbd
     abs input config values
  
 Frontend:
  1. Variable usage cleanup.  Now using the fb variables
     in most cases.  Only two fields added to main struct
  2. Removed resize event send in xenfb_resume().  There is 
     a general race condition where the vnc view will be left 
     at 600x400 if attached to too early.  (Not resize related)
  3. Removed refresh call in xenfb_resize_screen(), back end 
     invalidates buffer in resize event handler now
  4. xenkbd gets width and height for abs input in Connected

After I get some feed back, will wait a day or two, I will 
prepare a proper patch set.

Pat


[-- Attachment #2: fbback-resize.patch --]
[-- Type: text/x-patch, Size: 6113 bytes --]

diff -r 854b0704962b tools/ioemu/hw/xenfb.c
--- a/tools/ioemu/hw/xenfb.c	Wed Mar 05 09:43:03 2008 +0000
+++ b/tools/ioemu/hw/xenfb.c	Fri Mar 07 13:44:09 2008 -0600
@@ -516,6 +516,15 @@ 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;
+			/* Disable video buf sharing, not compatable with resizing */
+			dpy_colourdepth(xenfb->ds, 0);
+			dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
+			xenfb_invalidate(xenfb);
+			break;
 		}
 	}
 	xen_mb();		/* ensure we're done with ring contents */
@@ -680,6 +689,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;
 
         if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update",
                             "%d", &val) < 0)
@@ -702,10 +712,30 @@ static int xenfb_read_frontend_fb_config
         /* 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 max allowed */
+        if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.nodename, "videoram", "%d",
+                            &videoram) < 0)
+                videoram = 0;
+        videoram = videoram * 1024 * 1024;
+        if (videoram && xenfb->fb_len > videoram) {
+                fprintf(stderr, "Framebuffer requested length of %d exceded allowed %d\n",
+                        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)
 		return -1;
+
+        /* Indicate we have the frame buffer resize feature */
+        xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
+
+        /* Tell kbd pointer the screen geometry */
+        xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "width", "%d", xenfb->width);
+        xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "height", "%d", xenfb->height);
 
         if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
                 return -1;
diff -r 854b0704962b tools/python/xen/xend/server/vfbif.py
--- a/tools/python/xen/xend/server/vfbif.py	Wed Mar 05 09:43:03 2008 +0000
+++ b/tools/python/xen/xend/server/vfbif.py	Thu Mar 06 11:12:17 2008 -0600
@@ -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 854b0704962b tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py	Wed Mar 05 09:43:03 2008 +0000
+++ b/tools/python/xen/xm/create.py	Fri Mar 07 13:12:52 2008 -0600
@@ -500,6 +500,11 @@ 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="""Maximum 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?""")
@@ -641,7 +646,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 854b0704962b xen/include/public/io/fbif.h
--- a/xen/include/public/io/fbif.h	Wed Mar 05 09:43:03 2008 +0000
+++ b/xen/include/public/io/fbif.h	Thu Mar 06 11:12:17 2008 -0600
@@ -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;   /* depth in bits */
+};
+
 #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,15 +125,17 @@ 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.
+ * Wart: xenkbd needs to know default resolution.  Put it here until a
+ * better solution is found, but don't leak it to the backend.
  */
 #ifdef __KERNEL__
 #define XENFB_WIDTH 800

[-- Attachment #3: fbfront-resize.patch --]
[-- Type: text/x-patch, Size: 12482 bytes --]

diff -r 1cf7ba68d855 drivers/xen/fbfront/xenfb.c
--- a/drivers/xen/fbfront/xenfb.c	Mon Mar 03 13:36:57 2008 +0000
+++ b/drivers/xen/fbfront/xenfb.c	Fri Mar 07 21:21:44 2008 -0600
@@ -62,6 +62,8 @@ 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;     /* XENFB_TYPE_RESIZE needed */
 
 	struct xenbus_device	*xbdev;
 };
@@ -129,20 +131,42 @@ struct xenfb_info
  *
  * Oh well, we wont be updating the writes to this page anytime soon.
  */
+#define MB_ (1024*1024)
+#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
+
+enum {KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT};
+static int video[KPARAM_CNT] = {2, XENFB_WIDTH, XENFB_HEIGHT};
+module_param_array(video, int, NULL, 0);
+MODULE_PARM_DESC(video, 
+		"Size of video memory in MB and width,height in pixels, default = (2,800,600)");
 
 static int xenfb_fps = 20;
-static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
 
 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 *, int, int, int, int);
+
+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 +174,22 @@ 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->fb_info->var.xres;
+	event.resize.height = info->fb_info->var.yres;
+	event.resize.stride = info->fb_info->fix.line_length;
+	event.resize.depth = info->fb_info->var.bits_per_pixel;
+
+	/* caller ensures !xenfb_queue_full() */
+	xenfb_send_event(info, &event);
 }
 
 static int xenfb_queue_full(struct xenfb_info *info)
@@ -209,11 +241,23 @@ 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);
+}
+
 static int xenfb_thread(void *data)
 {
 	struct xenfb_info *info = data;
 
 	while (!kthread_should_stop()) {
+		if (info->resize_dpy) {
+			xenfb_resize_screen(info);
+		}
 		if (info->dirty) {
 			info->dirty = 0;
 			xenfb_update_screen(info);
@@ -413,6 +457,45 @@ 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;
+	int required_mem_len;
+
+	xenfb_info = info->par;
+
+	if (!xenfb_info->feature_resize) {
+		if (var->xres == video[KPARAM_WIDTH] && 
+				var->yres == video[KPARAM_HEIGHT] &&
+				var->bits_per_pixel == xenfb_info->page->depth) {
+			return 0;
+		}
+		return -EINVAL;
+	}
+	required_mem_len = var->xres * var->yres * (xenfb_info->page->depth / 8);
+	if (var->bits_per_pixel == xenfb_info->page->depth && 
+			var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) && 
+			required_mem_len <= info->fix.smem_len) {
+		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;
+
+	info->var.xres_virtual = info->var.xres;
+	info->var.yres_virtual = info->var.yres;
+	xenfb_info->resize_dpy = 1;
+	return 0;
+}
+
 static struct fb_ops xenfb_fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_setcolreg	= xenfb_setcolreg,
@@ -420,6 +503,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 +535,8 @@ static int __devinit xenfb_probe(struct 
 {
 	struct xenfb_info *info;
 	struct fb_info *fb_info;
+	int fb_size;
+	int val = 0;
 	int ret;
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -457,6 +544,21 @@ static int __devinit xenfb_probe(struct 
 		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
 		return -ENOMEM;
 	}
+
+	/* Limit kernel param videoram amount to what is in xenstore */
+	if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
+		if (val < video[KPARAM_MEM]) 
+			video[KPARAM_MEM] = val;
+	}
+
+	/* If requested res does not fit in available memory, use default */
+	fb_size = video[KPARAM_MEM] * MB_;
+	if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH/8 > fb_size) {
+		video[KPARAM_WIDTH] = XENFB_WIDTH;
+		video[KPARAM_HEIGHT] = XENFB_HEIGHT;
+		fb_size = XENFB_DEFAULT_FB_LEN;
+	}
+
 	dev->dev.driver_data = info;
 	info->xbdev = dev;
 	info->irq = -1;
@@ -469,12 +571,12 @@ static int __devinit xenfb_probe(struct 
 	info->refresh.data = (unsigned long)info;
 	INIT_LIST_HEAD(&info->mappings);
 
-	info->fb = vmalloc(xenfb_mem_len);
+	info->fb = vmalloc(fb_size);
 	if (info->fb == NULL)
 		goto error_nomem;
-	memset(info->fb, 0, xenfb_mem_len);
-
-	info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	memset(info->fb, 0, fb_size);
+
+	info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
 	info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
 			      GFP_KERNEL);
@@ -489,8 +591,6 @@ static int __devinit xenfb_probe(struct 
 	info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 	if (!info->page)
 		goto error_nomem;
-
-	xenfb_init_shared_page(info);
 
 	fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
 				/* see fishy hackery below */
@@ -504,9 +604,9 @@ 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.bits_per_pixel = info->page->depth;
+	fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH];
+	fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT];
+	fb_info->var.bits_per_pixel = XENFB_DEPTH;
 
 	fb_info->var.red = (struct fb_bitfield){16, 8, 0};
 	fb_info->var.green = (struct fb_bitfield){8, 8, 0};
@@ -518,9 +618,9 @@ static int __devinit xenfb_probe(struct 
 	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.line_length = fb_info->var.xres * (XENFB_DEPTH / 8);
 	fb_info->fix.smem_start = 0;
-	fb_info->fix.smem_len = xenfb_mem_len;
+	fb_info->fix.smem_len = fb_size;
 	strcpy(fb_info->fix.id, "xen");
 	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
 	fb_info->fix.accel = FB_ACCEL_NONE;
@@ -534,14 +634,18 @@ static int __devinit xenfb_probe(struct 
 		goto error;
 	}
 
+	/* init shared page, uses fb_info attributes */
+	info->fb_info = fb_info;
+	xenfb_init_shared_page(info);
+
 	ret = register_framebuffer(fb_info);
 	if (ret) {
 		fb_dealloc_cmap(&info->fb_info->cmap);
 		framebuffer_release(fb_info);
+		info->fb_info = NULL;
 		xenbus_dev_fatal(dev, ret, "register_framebuffer");
 		goto error;
 	}
-	info->fb_info = fb_info;
 
 	/* FIXME should this be delayed until backend XenbusStateConnected? */
 	info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
@@ -600,6 +704,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,13 +712,14 @@ 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;
-	info->page->depth = XENFB_DEPTH;
-	info->page->line_length = (info->page->depth / 8) * info->page->width;
-	info->page->mem_length = xenfb_mem_len;
+	for (i = 0; i * epd < info->nr_pages; i++) 
+		info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]);
+
+	info->page->width = info->fb_info->var.xres;
+	info->page->height = info->fb_info->var.yres;
+	info->page->depth = info->fb_info->var.bits_per_pixel;
+	info->page->line_length = info->fb_info->fix.line_length;
+	info->page->mem_length = info->fb_info->fix.smem_len;
 	info->page->in_cons = info->page->in_prod = 0;
 	info->page->out_cons = info->page->out_prod = 0;
 }
@@ -710,6 +816,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 1cf7ba68d855 drivers/xen/fbfront/xenkbd.c
--- a/drivers/xen/fbfront/xenkbd.c	Mon Mar 03 13:36:57 2008 +0000
+++ b/drivers/xen/fbfront/xenkbd.c	Fri Mar 07 16:57:34 2008 -0600
@@ -295,6 +295,16 @@ static void xenkbd_backend_changed(struc
 		 */
 		if (dev->state != XenbusStateConnected)
 			goto InitWait; /* no InitWait seen yet, fudge it */
+
+		/* Set input abs params to match backend screen res */
+		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				   "width", "%d", &val) > 0 )
+			input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
+
+		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				   "height", "%d", &val) > 0 )
+			input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
+
 		break;
 
 	case XenbusStateClosing:
diff -r 1cf7ba68d855 include/xen/interface/io/fbif.h
--- a/include/xen/interface/io/fbif.h	Mon Mar 03 13:36:57 2008 +0000
+++ b/include/xen/interface/io/fbif.h	Fri Mar 07 13:46:35 2008 -0600
@@ -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;   /* depth in bits */
+};
+
 #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,15 +125,17 @@ 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.
+ * Wart: xenkbd needs to know default resolution.  Put it here until a
+ * better solution is found, but don't leak it to the backend.
  */
 #ifdef __KERNEL__
 #define XENFB_WIDTH 800

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

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

^ permalink raw reply	[flat|nested] 29+ messages in thread
* [RFC] Dynamic modes support for PV xenfb (included)
@ 2008-01-28  0:48 Pat Campbell
  2008-01-28  8:07 ` Keir Fraser
                   ` (3 more replies)
  0 siblings, 4 replies; 29+ messages in thread
From: Pat Campbell @ 2008-01-28  0:48 UTC (permalink / raw)
  To: xen-devel@lists.xensource.com, Markus Armbruster,
	Daniel P. Berrange

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

Enough of the implementation has changed so I decided to go through
another RFC cycle.

What this patch does
   Allows PV framebuffer to be resized via xrandr or fbset and to start
   up the GUI at higher than 800x600

What is new in this iteration:
   1. No longer extending pd[] for extra memory
   2. New kernel xenfb.videomem param
   3. Added new events for extended FB memory mapping
   4. Extending FB memory via gntdev, supports up to 20MB
      on 64 bit guest, 40MB for a 32 bit guest.  Uses a two
      level grant table.
   5. xenkbd exported func to set pointer screen geometry
   6. Removed "wart" from fbif.h

New kernel xenfb param:
    videomem array,  FB size in MB, max scanline length
    vm config ie:
          extra="xenfb.videomem=5,1024 "

Setup instructions:
 1. Apply xen-fbfront-resize.patch to the Xen 3.2 PV guest kernel source,
    make and install
 2. Add modes line to guest xorg.conf and adjust monitor section if
    necessary
 3. Add extra kernel param to guest config file and set into xenstore
 4. Apply xen-fbback-resize.patch to xen-unstable tip, make and install
    Really only need the new qemu-dm to be installed

Screen should start out at 800x600 in the console and then switch to
whatever resolution you specified in xorg.conf for the GUI.  Switching 
to the console will revert screen to 800x600.

X11 fbdev will use the builtin resolution of 800x600 if alternate modes are
not specified in xorg.conf.

xorg.conf settings I used:

Section "Monitor"
  HorizSync    30-65
  Identifier   "Monitor[0]"
  ModelName    "XEN PV"
  VendorName   "XEN"
  VertRefresh  43-75
  UseModes     "Modes[0]"
EndSection

Section "Modes"
  Identifier   "Modes[0]"
  Modeline  "1024x768" 79.52 1024 1080 1192 1360 768 769 772 801
  Modeline  "800x600" 47.53 800 840 920 1040 600 601 604 626
  Modeline  "640x480" 29.84 640 664 728 816 480 481 484 501
EndSection

Section "Screen"
  SubSection "Display"
    Depth      24
    Modes      "1024x768" "800x600" "640x480"
  EndSubSection
  Device       "Device[0]"
  Identifier   "Screen[0]"
  Monitor      "Monitor[0]"
EndSection

Will appreciate any feedback

Pat


[-- Attachment #2: xen-fbback-resize.patch --]
[-- Type: text/x-patch, Size: 9558 bytes --]

diff -r 1c826ea72a80 tools/ioemu/hw/xenfb.c
--- a/tools/ioemu/hw/xenfb.c	Wed Jan 23 15:42:52 2008 +0000
+++ b/tools/ioemu/hw/xenfb.c	Thu Jan 24 08:26:55 2008 -0700
@@ -8,6 +8,7 @@
 #include <xen/io/fbif.h>
 #include <xen/io/kbdif.h>
 #include <xen/io/protocols.h>
+#include <xen/grant_table.h>
 #include <stdbool.h>
 #include <xen/event_channel.h>
 #include <sys/mman.h>
@@ -45,6 +46,7 @@ struct xenfb {
 	struct xs_handle *xsh;	/* xs daemon handle */
 	struct xenfb_device fb, kbd;
 	void *pixels;           /* guest framebuffer data */
+	void *old_pixels;       /* guest FB data before remapping to extended */
 	size_t fb_len;		/* size of framebuffer */
 	int row_stride;         /* width of one row in framebuffer */
 	int depth;              /* colour depth of guest framebuffer */
@@ -52,7 +54,9 @@ struct xenfb {
 	int height;             /* pixel height of guest framebuffer */
 	int abs_pointer_wanted; /* Whether guest supports absolute pointer */
 	int button_state;       /* Last seen pointer button state */
-	char protocol[64];	/* frontend protocol */
+	char protocol[64];      /* frontend protocol */
+	int otherend_bsize;     /* frontend bit size */
+	int gnttabdev;          
 };
 
 /* Functions for frontend/backend state machine*/
@@ -78,6 +82,8 @@ static void xenfb_invalidate(void *opaqu
 static void xenfb_invalidate(void *opaque);
 static void xenfb_screen_dump(void *opaque, const char *name);
 static int xenfb_register_console(struct xenfb *xenfb);
+static void xenfb_map_extended_fb(struct xenfb *xenfb, int, int, int);
+static int xenfb_send_map_extended_done(struct xenfb *xenfb);
 
 /*
  * Tables to map from scancode to Linux input layer keycode.
@@ -261,9 +267,19 @@ struct xenfb *xenfb_new(int domid, Displ
 	if (!xenfb->xsh)
 		goto fail;
 
+	xenfb->gnttabdev = xc_gnttab_open();
+	if (xenfb->gnttabdev == -1) {
+		fprintf(stderr, "FB: Can't open gnttab device\n");
+	}
+
 	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, requires grant tables */
+	if (xenfb->gnttabdev > 0) {
+		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);
@@ -320,6 +336,58 @@ static void xenfb_copy_mfns(int mode, in
 
 	for (i = 0; i < count; i++)
 		dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static void xenfb_map_extended_fb(struct xenfb *xenfb, int extended_mem_length, 
+		int gref_cnt, int gref)
+{
+	int n_fbmfns;
+	unsigned long *fbmfns = NULL;
+	void *page;	
+	int i;
+	int ep_gref;
+	int amt;
+	int index;
+	void *pixels;
+	int *grefs;
+
+	grefs = xc_gnttab_map_grant_ref (xenfb->gnttabdev, 
+			xenfb->fb.otherend_id,
+			gref, 0);
+	if (NULL == grefs) {
+		fprintf(stderr,"FB: Can't map to grant refs\n");
+		return;
+	}
+	n_fbmfns = (extended_mem_length + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+	fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
+	if (fbmfns) {
+		ep_gref = PAGE_SIZE/(xenfb->otherend_bsize/8);
+		amt = index = 0;
+		for(i = 0; i < gref_cnt; i++) {
+			page = xc_gnttab_map_grant_ref (xenfb->gnttabdev, 
+					xenfb->fb.otherend_id,
+					grefs[i], 0);
+			if (page) {
+				index = i * ep_gref;
+				amt = ep_gref;
+				if (n_fbmfns - index < ep_gref)
+					amt = n_fbmfns - index;
+				xenfb_copy_mfns(xenfb->otherend_bsize, amt, &fbmfns[index], page);
+				xc_gnttab_munmap(xenfb->gnttabdev, page, 1);
+			}
+			else
+				goto gref_error;
+		}
+		pixels = xc_map_foreign_pages(xenfb->xc, xenfb->fb.otherend_id,
+				PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
+		if (pixels) {
+			xenfb->old_pixels = xenfb->pixels;
+			xenfb->pixels = pixels;
+		}
+		free(fbmfns);
+	}
+gref_error:
+	xc_gnttab_munmap(xenfb->gnttabdev, grefs, 1);
 }
 
 static int xenfb_map_fb(struct xenfb *xenfb, int domid)
@@ -377,6 +445,7 @@ static int xenfb_map_fb(struct xenfb *xe
 #endif
 	}
 
+	xenfb->otherend_bsize = mode;
 	n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
 	n_fbdirs = n_fbmfns * mode / 8;
 	n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
@@ -456,6 +525,10 @@ static void xenfb_detach_dom(struct xenf
 		munmap(xenfb->pixels, xenfb->fb_len);
 		xenfb->pixels = NULL;
 	}
+	if (xenfb->old_pixels) {
+		munmap(xenfb->old_pixels, xenfb->fb_len);
+		xenfb->old_pixels = NULL;
+	}
 }
 
 /* Remove the backend area in xenbus since the framebuffer really is
@@ -473,6 +546,9 @@ void xenfb_shutdown(struct xenfb *xenfb)
 		xc_evtchn_close(xenfb->evt_xch);
 	if (xenfb->xsh)
 		xs_daemon_close(xenfb->xsh);
+	if (xenfb->gnttabdev > 0)
+		xc_gnttab_close(xenfb->gnttabdev);
+
 	free(xenfb);
 }
 
@@ -510,6 +586,21 @@ 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;
+		case XENFB_TYPE_MAP_EXTENDED:
+			if (xenfb->gnttabdev > 0) {
+				xenfb_map_extended_fb(xenfb, 
+						event->map_extended.extended_mem_length,
+						event->map_extended.gref_cnt,
+						event->map_extended.gref);
+			}
+			xenfb_send_map_extended_done(xenfb);
+			break;
 		}
 	}
 	mb();			/* ensure we're done with ring contents */
@@ -554,6 +645,41 @@ static int xenfb_on_state_change(struct 
 	}
 	return 0;
 }
+
+/* Send an event to the framebuffer frontend driver */
+static int xenfb_fb_event(struct xenfb *xenfb,
+		union xenfb_in_event *event)
+{
+	uint32_t prod;
+	struct xenfb_page *page = xenfb->fb.page;
+
+	if (xenfb->fb.state != XenbusStateConnected)
+		return 0;
+
+	prod = page->in_prod;
+	if (prod - page->in_cons == XENFB_IN_RING_LEN) {
+		errno = EAGAIN;
+		return -1;
+	}
+
+	mb();			/* ensure ring space available */
+	XENFB_IN_RING_REF(page, prod) = *event;
+	wmb();			/* ensure ring contents visible */
+	page->in_prod = prod + 1;
+	return xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+/* Send extended memory map done event to fb driver */
+static int xenfb_send_map_extended_done(struct xenfb *xenfb)
+{
+	union xenfb_in_event event;
+
+	memset(&event, 0, XENFB_IN_EVENT_SIZE);
+	event.type = XENFB_TYPE_MAP_EXTENDED_DONE;
+
+	return xenfb_fb_event(xenfb, &event);
+}
+
 
 /* Send an event to the keyboard frontend driver */
 static int xenfb_kbd_event(struct xenfb *xenfb,
diff -r 1c826ea72a80 xen/include/public/io/fbif.h
--- a/xen/include/public/io/fbif.h	Wed Jan 23 15:42:52 2008 +0000
+++ b/xen/include/public/io/fbif.h	Thu Jan 24 08:26:55 2008 -0700
@@ -29,8 +29,9 @@
 /* Out events (frontend -> backend) */
 
 /*
- * Out events may be sent only when requested by backend, and receipt
- * of an unknown out event is an error.
+ * Out event update is sent only when requested by backend
+ * Events resize and map_extended are frontend generated
+ * It is an error to send any unknown event types 
  */
 
 /* Event type 1 currently not used */
@@ -50,12 +51,44 @@ 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 */
+};
+
+/*
+ * Framebuffer map extended memory event
+ * Backend maps extended frame buffer memory
+ * for larger screen resolution support
+ */
+#define XENFB_TYPE_MAP_EXTENDED 4
+
+struct xenfb_map_extended
+{
+    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED */
+    int32_t extended_mem_length;    /* extended frame buffer len (in bytes) */
+    int32_t gref_cnt;               /* number of mapping refernces used */
+    int32_t gref;                   /* reference to mapping references */ 
+};
+
 #define XENFB_OUT_EVENT_SIZE 40
 
 union xenfb_out_event
 {
     uint8_t type;
     struct xenfb_update update;
+    struct xenfb_resize resize;
+    struct xenfb_map_extended map_extended;
     char pad[XENFB_OUT_EVENT_SIZE];
 };
 
@@ -63,14 +96,26 @@ union xenfb_out_event
 
 /*
  * Frontends should ignore unknown in events.
- * No in events currently defined.
  */
+
+/*
+ * Framebuffer map extended memory done event
+ * Frontend ends foreign access to extended memory
+ * grant table references
+ */
+#define XENFB_TYPE_MAP_EXTENDED_DONE 1
+
+struct xenfb_map_extended_done
+{
+    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED_DONE */
+};
 
 #define XENFB_IN_EVENT_SIZE 40
 
 union xenfb_in_event
 {
     uint8_t type;
+    struct xenfb_map_extended_done map_extended_done;
     char pad[XENFB_IN_EVENT_SIZE];
 };
 
@@ -115,16 +160,6 @@ struct xenfb_page
     unsigned long pd[2];
 };
 
-/*
- * 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 1c826ea72a80 xen/include/public/io/kbdif.h
--- a/xen/include/public/io/kbdif.h	Wed Jan 23 15:42:52 2008 +0000
+++ b/xen/include/public/io/kbdif.h	Thu Jan 24 08:26:55 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
 
 /*

[-- Attachment #3: xen-fbfront-resize.patch --]
[-- Type: text/x-patch, Size: 16967 bytes --]

diff -r 947e0701cf7a drivers/xen/fbfront/xenfb.c
--- a/drivers/xen/fbfront/xenfb.c	Tue Jan 22 21:52:44 2008 +0000
+++ b/drivers/xen/fbfront/xenfb.c	Thu Jan 24 08:27:06 2008 -0700
@@ -27,7 +27,9 @@
 #include <linux/mutex.h>
 #include <asm/hypervisor.h>
 #include <xen/evtchn.h>
+#include <xen/gnttab.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 +64,18 @@ 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_stride;      /* fb stride in bytes */
+	int			extended_mem;   /* fb is using extended mem */
+
+	grant_ref_t gref_head;
+	uint32_t gref_cnt;          /* number of grant refernces used */
+	int * grefs;                /* references for mfns */
+	int gref;                   /* reference to mfn references */
 
 	struct xenbus_device	*xbdev;
 };
@@ -129,20 +143,49 @@ struct xenfb_info
  *
  * Oh well, we wont be updating the writes to this page anytime soon.
  */
+static int videomem[2] = {0};
+static int videomem_cnt = 0;
+module_param_array(videomem, int, &videomem_cnt, 0);
+MODULE_PARM_DESC(videomem, 
+		"Size of video memory in MB and width in pixels, default = (2,800)");
+
+#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_MAX_GREF_CNT  10   /* enough for 32 bit:41MB  64 bit:20MB extended frame buffer */
+#define XENFB_MAX_FB_MEM (PAGE_SIZE/sizeof(long) * PAGE_SIZE * XENFB_MAX_GREF_CNT)
+#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 +193,31 @@ 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 void xenfb_do_map_extended(struct xenfb_info *info)
+{
+	union xenfb_out_event event;
+
+	event.type = XENFB_TYPE_MAP_EXTENDED;
+	event.map_extended.extended_mem_length = info->fb_size;
+	event.map_extended.gref_cnt = info->gref_cnt;
+	event.map_extended.gref = info->gref;
+
+	xenfb_send_event(info, &event);
 }
 
 static int xenfb_queue_full(struct xenfb_info *info)
@@ -209,6 +269,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 +287,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 +486,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 || !xenfb_info->extended_mem) {
+		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,23 +534,47 @@ 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,
 				       struct pt_regs *regs)
 {
-	/*
-	 * No in events recognized, simply ignore them all.
-	 * If you need to recognize some, see xenbkd's input_handler()
-	 * for how to do that.
-	 */
 	struct xenfb_info *info = dev_id;
 	struct xenfb_page *page = info->page;
 
-	if (page->in_cons != page->in_prod) {
-		info->page->in_cons = info->page->in_prod;
-		notify_remote_via_irq(info->irq);
-	}
+	__u32 cons, prod;
+	int i;
+
+	prod = page->in_prod;
+	if (prod == page->out_cons)
+		return IRQ_HANDLED;
+	rmb();			/* ensure we see ring contents up to prod */
+	for (cons = page->in_cons; cons != prod; cons++) {
+		union xenfb_in_event *event;
+		event = &XENFB_IN_RING_REF(page, cons);
+
+		switch (event->type) {
+			case XENFB_TYPE_MAP_EXTENDED_DONE:
+				gnttab_end_foreign_access_ref(info->gref);
+				gnttab_release_grant_reference( &info->gref_head, info->gref);
+
+				for ( i = 0; i < info->gref_cnt; i++) {
+					gnttab_end_foreign_access_ref(info->grefs[i]);
+					gnttab_release_grant_reference( &info->gref_head, info->grefs[i]);
+				}
+                /* Map was being done during a resume, need to get the screen resized */
+                if (info->xres != XENFB_WIDTH || info->yres != XENFB_HEIGHT) {
+					info->resize_dpy = 1;
+				}
+				break;
+		}
+	}
+	mb();			/* ensure we got ring contents */
+	page->in_cons = cons;
+	notify_remote_via_irq(info->irq);
+
 	return IRQ_HANDLED;
 }
 
@@ -457,10 +595,24 @@ static int __devinit xenfb_probe(struct 
 		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
 		return -ENOMEM;
 	}
+
+	info->fb_size = XENFB_DEFAULT_FB_LEN;
+	info->fb_width = XENFB_WIDTH;
+	if (videomem_cnt == 2 && (videomem[0] * MB_) >= XENFB_DEFAULT_FB_LEN && 
+			(videomem[0] * MB_) <= XENFB_MAX_FB_MEM &&
+			videomem[1] >= XENFB_WIDTH) {
+		info->fb_size = videomem[0] * MB_;
+		info->fb_width = videomem[1];
+		info->extended_mem = 1;
+	}
+	xenfb_mem_len = info->fb_size;
+
 	dev->dev.driver_data = info;
 	info->xbdev = dev;
 	info->irq = -1;
 	info->x1 = info->y1 = INT_MAX;
+	info->xres = XENFB_WIDTH;
+	info->yres = XENFB_HEIGHT;
 	spin_lock_init(&info->dirty_lock);
 	mutex_init(&info->mm_lock);
 	init_waitqueue_head(&info->wq);
@@ -485,6 +637,11 @@ static int __devinit xenfb_probe(struct 
 	if (!info->mfns)
 		goto error_nomem;
 
+	info->grefs = vmalloc(sizeof(int) * (XENFB_MAX_GREF_CNT + 1));
+	if (!info->grefs)
+		goto error_nomem;
+	memset(info->grefs, 0, sizeof(int) * (XENFB_MAX_GREF_CNT + 1));
+
 	/* set up shared page */
 	info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 	if (!info->page)
@@ -504,9 +661,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};
@@ -592,6 +750,7 @@ static int xenfb_remove(struct xenbus_de
 	vfree(info->mfns);
 	kfree(info->pages);
 	vfree(info->fb);
+	vfree(info->grefs);
 	kfree(info);
 
 	return 0;
@@ -600,6 +759,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);
@@ -612,10 +772,32 @@ static void xenfb_init_shared_page(struc
 	info->page->width = XENFB_WIDTH;
 	info->page->height = XENFB_HEIGHT;
 	info->page->depth = XENFB_DEPTH;
-	info->page->line_length = (info->page->depth / 8) * info->page->width;
-	info->page->mem_length = xenfb_mem_len;
+	info->page->line_length = (info->page->depth / 8) * XENFB_WIDTH;
+	info->page->mem_length = XENFB_DEFAULT_FB_LEN;
 	info->page->in_cons = info->page->in_prod = 0;
 	info->page->out_cons = info->page->out_prod = 0;
+
+	if (info->extended_mem) {
+		info->fb_stride = (info->page->depth / 8) * info->fb_width;
+		if (gnttab_alloc_grant_references(XENFB_MAX_GREF_CNT + 1, &info->gref_head) == 0) {
+			info->gref = gnttab_claim_grant_reference(&info->gref_head);
+			gnttab_grant_foreign_access_ref(
+					info->gref,
+					info->xbdev->otherend_id, 
+					vmalloc_to_mfn(info->grefs), 0);
+			for (i = 0; i * epd < info->nr_pages; i++) {
+				info->grefs[i] = gnttab_claim_grant_reference(&info->gref_head);
+				gnttab_grant_foreign_access_ref( info->grefs[i],
+						info->xbdev->otherend_id,
+						vmalloc_to_mfn(&info->mfns[i * epd]), 0);
+			}
+			info->gref_cnt = i; 
+			gnttab_free_grant_references(info->gref_head);
+		}
+		if (!info->gref_cnt) {
+			info->extended_mem = 0;
+		}
+	}
 }
 
 static int xenfb_connect_backend(struct xenbus_device *dev,
@@ -710,6 +892,15 @@ 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;
+
+		if (info->feature_resize && info->extended_mem) {
+			xenfb_do_map_extended(info);
+		}
 		break;
 
 	case XenbusStateClosing:
@@ -744,6 +935,8 @@ static int __init xenfb_init(void)
 	if (is_initial_xendomain())
 		return -ENODEV;
 
+	xenkbd_set_ptr_geometry(XENFB_WIDTH, XENFB_HEIGHT);
+
 	return xenbus_register_frontend(&xenfb);
 }
 
diff -r 947e0701cf7a drivers/xen/fbfront/xenkbd.c
--- a/drivers/xen/fbfront/xenkbd.c	Tue Jan 22 21:52:44 2008 +0000
+++ b/drivers/xen/fbfront/xenkbd.c	Thu Jan 24 08:27:06 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 947e0701cf7a include/xen/interface/io/fbif.h
--- a/include/xen/interface/io/fbif.h	Tue Jan 22 21:52:44 2008 +0000
+++ b/include/xen/interface/io/fbif.h	Thu Jan 24 08:27:06 2008 -0700
@@ -29,8 +29,9 @@
 /* Out events (frontend -> backend) */
 
 /*
- * Out events may be sent only when requested by backend, and receipt
- * of an unknown out event is an error.
+ * Out event update is sent only when requested by backend
+ * Events resize and map_extended are frontend generated
+ * It is an error to send any unknown event types 
  */
 
 /* Event type 1 currently not used */
@@ -50,12 +51,44 @@ 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 */
+};
+
+/*
+ * Framebuffer map extended memory event
+ * Backend maps extended frame buffer memory
+ * for larger screen resolution support
+ */
+#define XENFB_TYPE_MAP_EXTENDED 4
+
+struct xenfb_map_extended
+{
+    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED */
+    int32_t extended_mem_length;    /* extended frame buffer len (in bytes) */
+    int32_t gref_cnt;               /* number of mapping refernces used */
+    int32_t gref;                   /* reference to mapping references */ 
+};
+
 #define XENFB_OUT_EVENT_SIZE 40
 
 union xenfb_out_event
 {
     uint8_t type;
     struct xenfb_update update;
+    struct xenfb_resize resize;
+    struct xenfb_map_extended map_extended;
     char pad[XENFB_OUT_EVENT_SIZE];
 };
 
@@ -63,14 +96,26 @@ union xenfb_out_event
 
 /*
  * Frontends should ignore unknown in events.
- * No in events currently defined.
  */
+
+/*
+ * Framebuffer map extended memory done event
+ * Frontend ends foreign access to extended memory
+ * grant table references
+ */
+#define XENFB_TYPE_MAP_EXTENDED_DONE 1
+
+struct xenfb_map_extended_done
+{
+    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED_DONE */
+};
 
 #define XENFB_IN_EVENT_SIZE 40
 
 union xenfb_in_event
 {
     uint8_t type;
+    struct xenfb_map_extended_done map_extended_done;
     char pad[XENFB_IN_EVENT_SIZE];
 };
 
@@ -115,16 +160,6 @@ struct xenfb_page
     unsigned long pd[2];
 };
 
-/*
- * 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 947e0701cf7a include/xen/interface/io/kbdif.h
--- a/include/xen/interface/io/kbdif.h	Tue Jan 22 21:52:44 2008 +0000
+++ b/include/xen/interface/io/kbdif.h	Thu Jan 24 08:27:06 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
 
 /*

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

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

^ permalink raw reply	[flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
@ 2007-12-31 12:27 Pat Campbell
  2008-01-02 10:51 ` Gerd Hoffmann
  0 siblings, 1 reply; 29+ messages in thread
From: Pat Campbell @ 2007-12-31 12:27 UTC (permalink / raw)
  To: Mark Williamson, xen-devel

>>> On Sun, Dec 23, 2007 at  2:58 PM, in message
<200712232158.13581.mark.williamson@cl.cam.ac.uk>, Mark Williamson
<mark.williamson@cl.cam.ac.uk> wrote: 
>>  The attached files allow the PV framebuffer to be dynamically resized from
>> 800x600 to 1024x768 and back.
>>
>> xen-fbfront-resize.patch is applied to tip of linux-2.6.18-xen
>> xen-fbback-resize.patch is applied to tip of unstable-xen
> 
>> I am NOT requesting commit to xen- unstable. This is just a posting
>> for code review  and feedback.
>>
>> After the patches  are applied to dom0 and your domU
>> PV guest you will need to properly configure the domU X
>> server for display modes 800x600 and 1024x768.
> 
> Nice.
> 
> I took a quite look through the code and was impressed by how small a patch 
> was actually required.
> 
> A few general comments:
> 1) I think it would be preferable to be able to dynamically size the memory 
> allocated to the framebuffer according to the resolution, rather than 
> statically allocating it and then potentially not using all of it.  
> Presumably this would require more extensive changes to the backend, since 
> it 
> would need to map and unmap the framebuffer memory during a resize 
> operation.  
> How complicated do you think this would be?

I am not familiar enough with the Linux frame buffer code to even hazard 
a guess.  Once the frame buffer is registered in the probe function can the
memory be changed without crashing the app that has mmaped it in?  
Handshake with the backend would complicate things, need to disable shared
memory access, remapped it and then reenable it.  Not sure how suspend 
resume might work in this case.

Absolute mouse positioning needs to know the resolution to scale the 
position properly.  Need some new events to alert it of a resolution change.

> 
> 2) Dynamically allocating the memory would make it practical to support a 
> larger range of resultions than currently possible, without wasting lots of 
> memory for potential higher resolutions (e.g. to suit users with very big 
> monitors connected to dom0).
> 
> I think that this is nice support to have available.  Other VMM user 
> interfaces even allow resizing of the guest display resolution simply by 
> resizing the viewer window on the host - this would require a little more 
> software running in the guest to support it but would be cool to support.  
> Of 
> course, that's just me getting excited - simply supporting resize from 
> within 
> the guest is a major win in practicality.
> 
> Do you have any further plans for xenfb?  It's not got as much love as it 
> could have done and it definitely seems like there are things that can be 
> done to improve it still further.

No further plans at the moment.  I looked into using grant tables for the
shared memory but decided against it for now.  Grant tables would break
backwards compatibility unless both memory sharing techniques were
supported. 

> 
> Cheers,
> Mark

Thanks for taking the time to look at it.

Pat
> 
>> For testing I used "xrandr" to dynamically resize the domU
>> GUI session.
>>
>> >$ xrandr       // show capabilities
>>
>>  SZ:    Pixels          Physical       Refresh
>>  *0   1024 x 768    ( 361mm x 291mm )  *73
>>   1    800 x 600    ( 361mm x 291mm )   73
>>   Current rotation - normal
>>   Current reflection - none
>>   Rotations possible - normal
>>   Reflections possible - none
>>
>> >$ xrandr --size 800x600     //change to 800x600
>> >$ xrandr --size 1024x768
>>
>> domU xorg.conf :
>>  SuSE sax2 is not able to configure a PV framebuffer properly
>>  so I hand crafted a new xorg.conf file for the PV guest. Below
>>  are the sections I changed.
>>
>> Section "Monitor"
>>   HorizSync    30-65
>>   Identifier   "Monitor[0]"
>>   ModelName    "XEN PVFB"
>>   Option       "DPMS"
>>   VendorName   "XEN"
>>   VertRefresh  43-75
>>   UseModes     "Modes[0]"
>> EndSection
>>
>> Section "Modes"
>>   Identifier   "Modes[0]"
>>   Modeline  "1024x768" 77.25 1024 1080 1192 1360 768 769 772 800
>>   Modeline  "800x600" 46.15 800 840 920 1040 600 601 604 625
>> EndSection
>>
>> Section "Screen"
>>   SubSection "Display"
>>     Depth      24
>>     Modes      "1024x768" "800x600"
>>   EndSubSection
>>   Device       "Device[0]"
>>   Identifier   "Screen[0]"
>>   Monitor      "Monitor[0]"
>> EndSection
>>
>> Pat
> 
> 
> 
> -- 
> Dave: Just a question. What use is a unicyle with no seat?  And no pedals!
> Mark: To answer a question with a question: What use is a skateboard?
> Dave: Skateboards have wheels.
> Mark: My wheel has a wheel!

^ permalink raw reply	[flat|nested] 29+ messages in thread
[parent not found: <476133BC0200001800606E1D@sinclair.provo.novell.com>]

end of thread, other threads:[~2008-03-14 16:39 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-02-04 18:49 [RFC]Dynamic modes support for PV xenfb (included) Pat Campbell
2008-02-05  9:52 ` Markus Armbruster
2008-02-05 23:38   ` Pat Campbell
2008-02-06 15:49     ` Markus Armbruster
  -- strict thread matches above, loose matches on Subject: below --
2008-03-09 21:19 [RFC] Dynamic " Pat Campbell
2008-03-09 21:29 ` Samuel Thibault
2008-03-10 12:36 ` Samuel Thibault
2008-03-10 16:16 ` Samuel Thibault
2008-03-10 16:36   ` Samuel Thibault
2008-03-12 17:04 ` Markus Armbruster
2008-03-13 13:05   ` Pat Campbell
2008-03-13 19:53     ` Pat Campbell
2008-03-14 16:39     ` Markus Armbruster
2008-01-28  0:48 Pat Campbell
2008-01-28  8:07 ` Keir Fraser
2008-01-30  9:43 ` Markus Armbruster
2008-01-30 13:41   ` Pat Campbell
2008-01-30 17:45     ` Markus Armbruster
2008-01-30 20:27       ` Pat Campbell
2008-01-31  8:22         ` Gerd Hoffmann
2008-01-31  8:50           ` Markus Armbruster
2008-01-31  9:06         ` Markus Armbruster
2008-01-30 20:43 ` Daniel P. Berrange
2008-02-28 10:36 ` Keir Fraser
2008-02-28 11:36   ` Markus Armbruster
2007-12-31 12:27 Pat Campbell
2008-01-02 10:51 ` Gerd Hoffmann
     [not found] <476133BC0200001800606E1D@sinclair.provo.novell.com>
     [not found] ` <476999300200001800607A16@sinclair.provo.novell.com>
2007-12-20  5:20   ` Pat Campbell
2007-12-23 21:58     ` Mark Williamson

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