Skip to contentSkip to conversation

Dynamic modes support for PV xenfb (included)

RFC In review Pat Campbell 2 participants 2 messages Dec 20, 2007 – Dec 23, 2007 2 messages not in the archive Xen hypervisor interface

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

RFC 1/1 Dynamic modes support for PV xenfb (included)

Hi,

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 have tested the patches on SuSE SLES 10:
x86_64 dom0 x86_64 domU OK
x386 domU OK
x386 dom0 x386 domU OK
x86_64 domU Error: (4, 'Out of memory',
xc_dom_boot_mem_init: can't allocate
low memory for domain)
( This is something else unrelated to my patch I think )

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.

For testing I used "xrandr" to dynamically resize the domU GUI session.

Quoted 1 line
$ 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

Quoted 2 lines
$ 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

drivers/xen/fbfront/xenfb.c +106 -8
diff -r 4344d531875b drivers/xen/fbfront/xenfb.c
@@ -62,6 +62,9 @@ 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;
 
 	struct xenbus_device	*xbdev;
 };
@@ -130,13 +133,18 @@ struct xenfb_info
  * Oh well, we wont be updating the writes to this page anytime soon.
  */
 
+#define XENFB_PIXCLOCK  9025  /* Xorg "1280x1024" 110.80 to FB 1000000/110.80 */ 
+#define XENFB_MAX_WIDTH 1024
+#define XENFB_MAX_HEIGHT 768
+
 static int xenfb_fps = 20;
-static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
+static unsigned long xenfb_mem_len = XENFB_MAX_WIDTH * XENFB_MAX_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 *info, int x1, int y1, int w, int h);
 
 static void xenfb_do_update(struct xenfb_info *info,
 			    int x, int y, int w, int h)
@@ -155,6 +163,25 @@ static void xenfb_do_update(struct xenfb
 	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_resize(struct xenfb_info *info)
+{
+	union xenfb_out_event event;
+	__u32 prod;
+
+	event.type = XENFB_TYPE_RESIZE;
+	event.resize.width = info->xres;
+	event.resize.height = info->yres;
+
+	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);
@@ -209,6 +236,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 +254,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 +453,46 @@ 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) {
+			return 0;
+		}
+		return -EINVAL;
+	}
+	if (var->xres == 1024 && var->yres == 768) {
+		return 0;
+	}
+	if (var->xres == 800 && var->yres == 600) {
+		return 0;
+	}
+	if (var->xres == 640 && var->yres == 480) {
+		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->xres = info->var.xres;
+		xenfb_info->yres = 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 +500,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,
@@ -461,6 +543,8 @@ static int __devinit xenfb_probe(struct 
 	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);
@@ -504,9 +588,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};
@@ -600,19 +685,27 @@ static void xenfb_init_shared_page(struc
 static void xenfb_init_shared_page(struct xenfb_info *info)
 {
 	int i;
-
+	int j;
+	int entries_per_pd;
+
+	entries_per_pd = PAGE_SIZE/ sizeof( unsigned long);
+	
 	for (i = 0; i < info->nr_pages; i++)
 		info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
 
-	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;
+	for ( j = i = 0; i < info->nr_pages; i++) {
+		info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
+		if ( i && i % entries_per_pd == 0 ) {
+			j++;
+			info->page->pd[j] = vmalloc_to_mfn(&info->mfns[i]);
+		}
+	}
 	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->line_length = (info->page->depth / 8) * XENFB_MAX_WIDTH;
 	info->page->mem_length = xenfb_mem_len;
 	info->page->in_cons = info->page->in_prod = 0;
 	info->page->out_cons = info->page->out_prod = 0;
@@ -710,6 +803,11 @@ static void xenfb_backend_changed(struct
 			val = 0;
 		if (val)
 			info->update_wanted = 1;
+		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+				 "feature-resize", "%d", &val) < 0)
+			val = 0;
+		if (val)
+			info->feature_resize = 1;
 		break;
 
 	case XenbusStateClosing:
include/xen/interface/io/fbif.h +14 -0
diff -r 4344d531875b include/xen/interface/io/fbif.h
@@ -50,12 +50,26 @@ 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;   /* xres */
+    int32_t height;  /* yres */
+};
+
 #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];
 };
 
tools/ioemu/hw/xenfb.c +10 -0
diff -r 4553bc1087d9 tools/ioemu/hw/xenfb.c
@@ -267,6 +267,9 @@ struct xenfb *xenfb_new(int domid, Displ
 
 	fprintf(stderr, "FB: Waiting for KBD backend creation\n");
 	xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
+
+	/* Indicate we have the frame buffer resize feature */
+	xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
 
 	return xenfb;
 
@@ -510,6 +513,13 @@ static void xenfb_on_fb_event(struct xen
 			}
 			xenfb_guest_copy(xenfb, x, y, w, h);
 			break;
+		case XENFB_TYPE_RESIZE:
+			w = event->resize.width;
+			h = event->resize.height;
+			xenfb->width = w;
+			xenfb->height = h;
+			dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
+			break;
 		}
 	}
 	mb();			/* ensure we're done with ring contents */
xen/include/public/io/fbif.h +14 -0
diff -r 4553bc1087d9 xen/include/public/io/fbif.h
@@ -50,12 +50,26 @@ 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;   /* xres */
+    int32_t height;  /* yres */
+};
+
 #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];
 };
 

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

#3 lore raw
Quoted 6 lines

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

Quoted 6 lines

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?

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.

Cheers,
Mark

Quoted 48 lines

For testing I used "xrandr" to dynamically resize the domU GUI session.

Quoted 1 line
$ 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

Quoted 2 lines
$ 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

Signature · 4 lines
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!