Skip to contentSkip to conversation

Dynamic modes support for PV xenfb (included)

RFC In review Pat Campbell 5 participants 12 messages Jan 28, 2008 – Feb 28, 2008 Xen hypervisor interface

lore
Share & tools
lore
#0 lore raw

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

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

tools/ioemu/hw/xenfb.c +127 -1
diff -r 1c826ea72a80 tools/ioemu/hw/xenfb.c
@@ -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,
xen/include/public/io/fbif.h +48 -13

98 lines not on this page · raw message

xen/include/public/io/kbdif.h +4 -0
diff -r 1c826ea72a80 xen/include/public/io/kbdif.h
@@ -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
 
 /*
drivers/xen/fbfront/xenfb.c +216 -23

363 lines not on this page · raw message

drivers/xen/fbfront/xenkbd.c +19 -3
diff -r 947e0701cf7a drivers/xen/fbfront/xenkbd.c
@@ -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);
 
include/xen/interface/io/fbif.h +48 -13

98 lines not on this page · raw message

include/xen/interface/io/kbdif.h +4 -0
diff -r 947e0701cf7a include/xen/interface/io/kbdif.h
@@ -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
[email protected]
http://lists.xensource.com/xen-devel

#1 lore raw
Quoted 3 lines · Pat Campbell

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.

Oh I see what you mean. I thought maybe you'd implemented a two-level grant table at the Xen hypervisor interface.

-- Keir

#2 lore raw
In reply to Pat Campbell

The current PVFB code shares the framebuffer as follows. The framebuffer is described by a two level directory. The first level is the page directory pd[] in the shared page. pd[] contains the mfns of the second level directory pages. Those form an array containing the mfns of the framebuffer.

Your patch replaces both levels of the page directory by grants, but not the framebuffer itself. What exactly does that buy us?

#3 lore raw
Quoted 9 lines · Markus Armbruster

The current PVFB code shares the framebuffer as follows. The framebuffer is described by a two level directory. The first level is the page directory pd[] in the shared page. pd[] contains the mfns of the second level directory pages. Those form an array containing the mfns of the framebuffer.

Your patch replaces both levels of the page directory by grants, but not the framebuffer itself. What exactly does that buy us?

Patch does not replace the pd array. That is still being used to maintain backwards compatibility. The required framebuffer memory is allocated in xenfb_probe() and is never reallocated or changed. Only the mapping to the framebuffer is changed.

Maybe some pseudo code this will make it clearer.

Frontend (FE)
Determine framebuffer size
Allocate framebuffer
Fill in array of mfns
Set shared page info to default mem length, width and height Fill in grant refs using array of mfns
Back end Connected?
Send map extended event (uses grant ref)
Map extended done event?
Free grant refs

Backend (BE)
Calculate number of mfns based on mem length from shared page Map in and point at framebuffer
Map extended event?
Map in using grant ref
Change framebuffer pointer to the new location
(still the same FE memory but now we can reach father
into it)
Send Map extended done

At this point the Backend is still treating the framebuffer as 800x600x32 but does has access to the extended framebuffer memory but does not use it. When a resize event occurs the screen geometry changes but not the framebuffers mappings.

So to answer what it buys us. It buys us access to a larger framebuffer for higher resolutions support.

#4 lore raw
Quoted 38 lines · Pat Campbell
Quoted 9 lines · Markus Armbruster

The current PVFB code shares the framebuffer as follows. The framebuffer is described by a two level directory. The first level is the page directory pd[] in the shared page. pd[] contains the mfns of the second level directory pages. Those form an array containing the mfns of the framebuffer.

Your patch replaces both levels of the page directory by grants, but not the framebuffer itself. What exactly does that buy us?

Patch does not replace the pd array. That is still being used to maintain backwards compatibility. The required framebuffer memory is allocated in xenfb_probe() and is never reallocated or changed. Only the mapping to the framebuffer is changed.

Maybe some pseudo code this will make it clearer.

Frontend (FE)
Determine framebuffer size
Allocate framebuffer
Fill in array of mfns
Set shared page info to default mem length, width and height Fill in grant refs using array of mfns
Back end Connected?
Send map extended event (uses grant ref)
Map extended done event?
Free grant refs

Backend (BE)
Calculate number of mfns based on mem length from shared page Map in and point at framebuffer
Map extended event?
Map in using grant ref
Change framebuffer pointer to the new location
(still the same FE memory but now we can reach father
into it)
Send Map extended done

Quoted 4 lines

At this point the Backend is still treating the framebuffer as 800x600x32 but does has access to the extended framebuffer memory but does not use it. When a resize event occurs the screen geometry changes but not the framebuffers mappings.

Understood.

Quoted 2 lines

So to answer what it buys us. It buys us access to a larger framebuffer for higher resolutions support.

I can't see how using grants for the page directory is an improvement over your previous iteration, which used pd[]. Can you explain?

#5 lore raw
Quoted 52 lines · Markus Armbruster
Quoted 40 lines · Pat Campbell
Quoted 10 lines · Markus Armbruster

The current PVFB code shares the framebuffer as follows. The framebuffer is described by a two level directory. The first level is the page directory pd[] in the shared page. pd[] contains the mfns of the second level directory pages. Those form an array containing the mfns of the framebuffer.

Your patch replaces both levels of the page directory by grants, but not the framebuffer itself. What exactly does that buy us?

Patch does not replace the pd array. That is still being used to maintain backwards compatibility. The required framebuffer memory is allocated in xenfb_probe() and is never reallocated or changed. Only the mapping to the framebuffer is changed.

Maybe some pseudo code this will make it clearer.

Frontend (FE)
Determine framebuffer size
Allocate framebuffer
Fill in array of mfns
Set shared page info to default mem length, width and height Fill in grant refs using array of mfns
Back end Connected?
Send map extended event (uses grant ref)
Map extended done event?
Free grant refs

Backend (BE)
Calculate number of mfns based on mem length from shared page Map in and point at framebuffer
Map extended event?
Map in using grant ref
Change framebuffer pointer to the new location
(still the same FE memory but now we can reach father
into it)
Send Map extended done

Quoted 5 lines

At this point the Backend is still treating the framebuffer as 800x600x32 but does has access to the extended framebuffer memory but does not use it. When a resize event occurs the screen geometry changes but not the framebuffers mappings.

Understood.

Quoted 7 lines
Quoted 3 lines

So to answer what it buys us. It buys us access to a larger framebuffer for higher resolutions support.

I can't see how using grants for the page directory is an improvement over your previous iteration, which used pd[]. Can you explain?

I will try, I am not the greatest communicator lately.

Previous iteration did use pd[] extending it to 3 from 2, this had the drawback of limiting our frame buffer size to a max of 6 MB for a 64 bit guest, 12mb for a 32 bit guest. 6MB can handle a maximum of 1280x1024 which in previous emails was deemed not enough.
HD 1080 1920x1200 requires 9MB (pd[5], 64bit)
WQXGA 2560x1600 requires 16MB (pd[8], 64bit)

I could of just extended pd[] some more to increase the available slots but every time we want to increase the total frame buffer size we have to compile both ends. Probably could just keep reading/mapping until we hit a NULL in the backend to eliminate that issue but that ends adding any new items to the shared info page.

By using grants:
I don't effect the current shared info
Don't have to deal with differences between a 64 bit long and a 32
bit long.
Single grant ref fits within the event structure

Are those benefits worth the code complexity that grants added? Not
sure. Other than grants, which I can remove and revert to pd[], are all the other issues that were raised addressed?

While I was working on this I "briefly" looked at the grant APIs to see how hard it would be to create a new API that allocates and claims a continuous block of references. If I had a guaranteed continuous block I would then only need to send the initial ref number and a count to the backend.

#6 lore raw
Quoted 5 lines · Pat Campbell
Quoted 3 lines · Markus Armbruster

I can't see how using grants for the page directory is an improvement over your previous iteration, which used pd[]. Can you explain?

I will try, I am not the greatest communicator lately.

The real question is why stop half-way with the grant tables conversion? You should put grant references instead of mfns into the page list pages, i.e. map the framebuffer itself using grants too. That will kill even more 32/64 bit differences btw.

Quoted 3 lines

While I was working on this I "briefly" looked at the grant APIs to see how hard it would be to create a new API that allocates and claims a continuous block of references.

You don't need that. xc_gnttab_map_grant_refs() takes a list of grant refs and creates a linear mapping of those for you.

Only problem is that gntdev has a 128 grants limit, this needs fixing. Derek?

cheers,
Gerd

Signature · 1 line
http://kraxel.fedorapeople.org/xenner/
#7 lore raw
Quoted 8 lines · Gerd Hoffmann
Quoted 5 lines · Pat Campbell
Quoted 3 lines · Markus Armbruster

I can't see how using grants for the page directory is an improvement over your previous iteration, which used pd[]. Can you explain?

I will try, I am not the greatest communicator lately.

The real question is why stop half-way with the grant tables conversion?

[...]

Precisely.

Since we need to stay backward compatible, stable interfaces tend to remain with us basically forever. Maintaining the current mfn-based interface plus a future interface fully based on grants seems okay to me. But please no intermediate steps.

#8 lore raw
In reply to Pat Campbell
Quoted 1 line · Pat Campbell

Markus Armbruster wrote:

[...]

Quoted 12 lines
Quoted 3 lines

I can't see how using grants for the page directory is an improvement over your previous iteration, which used pd[]. Can you explain?

I will try, I am not the greatest communicator lately.

Previous iteration did use pd[] extending it to 3 from 2, this had the drawback of limiting our frame buffer size to a max of 6 MB for a 64 bit guest, 12mb for a 32 bit guest. 6MB can handle a maximum of 1280x1024 which in previous emails was deemed not enough.
HD 1080 1920x1200 requires 9MB (pd[5], 64bit)
WQXGA 2560x1600 requires 16MB (pd[8], 64bit)

Quoted 5 lines

I could of just extended pd[] some more to increase the available slots but every time we want to increase the total frame buffer size we have to compile both ends. Probably could just keep reading/mapping until we hit a NULL in the backend to eliminate that issue but that ends adding any new items to the shared info page.

Every slot in pd[] gets us 2M (64 bit). The shared page has space left for about 500 slots. We can easily increase pd[] to 256 slots, good for 512M of framebuffer, or 128 Megapixels (>12000x10000), *and* leave plenty of space in the shared page for future uses.

The backend should map precisely as much framebuffer as the frontend tells it (struct xenfb_page member mem_length), using as much of pd[] as necessary for that.

Quoted 9 lines

By using grants:
I don't effect the current shared info
Don't have to deal with differences between a 64 bit long and a 32
bit long.
Single grant ref fits within the event structure

Are those benefits worth the code complexity that grants added? Not
sure. Other than grants, which I can remove and revert to pd[], are all the other issues that were raised addressed?

I haven't reviewed your patch in detail. The change in fb mapping stuck out, and I wanted it discussed before I do that. Assuming we can agree to extending pd[] instead, would you mind preparing a new patch for us to review?

[...]

#9 lore raw
In reply to Pat Campbell
Quoted 17 lines · Pat Campbell

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

Quoted 4 lines

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

On the one hand I like this because this gives the guest admin control over how much of their RAM they want to put aside for the FB. On the other hand I don't like this because it also impacts RAM allocation inside QEMU which is a denial of service attack on Dom0.

I was originally thinking that you'd put 'videomem' as a parameter in the PVFB config of the guest, eg

vfb = [ "type=vnc,vncunused=1,vnclisten=127.0.0.1,vncpasswd=,videoram=5" ]

I'm fine with it being a kernel param, as long as we also have a way for the Dom0 admin to specify a hard limit in the vfb= config option. A combo of both will allow flexibility for domU admin, and good control for the Dom0 admin.

Quoted 6 lines

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.

I don't have an answer for this problem, since its not my areas of expertise, but requiring manual xorg.conf settings is really not a very nice thing to deal with. Xorg is moving to a 100% auto-configured setup. With regular monitors it'll probe EDID or whatever to get display capabilities - obviously we don't have that capability, but I wonder if there's some way we can provide enough info to X so that it can automatically enable any of the resolutions without needing Modelines / Modes.

Ideally the out of the box config would allow X to auto-startup with zero config file, pick a resonable default resolution, and provide enough info to allow 'xrandr' to be used to resize to any resolution within the confines of the video RAM allocation.

Dan.

Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
#10 lore raw
In reply to Pat Campbell

Did everyone agree this version is good to go? I'll check it in if Dan and Markus will ack it.

-- Keir

Quoted 973 lines · Pat Campbell

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

diff -r 1c826ea72a80 tools/ioemu/hw/xenfb.c

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +1 -0
@@ -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 */

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +0 -0
@@ -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*/

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +12 -0
@@ -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);

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +52 -0
@@ -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)

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +23 -0
@@ -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 */

tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700 renamed from tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000 +35 -0
@@ -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

xen/include/public/io/fbif.h Thu Jan 24 08:26:55 2008 -0700 renamed from xen/include/public/io/fbif.h Wed Jan 23 15:42:52 2008 +0000 +48 -13
@@ -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

xen/include/public/io/kbdif.h Thu Jan 24 08:26:55 2008 -0700 renamed from xen/include/public/io/kbdif.h Wed Jan 23 15:42:52 2008 +0000 +4 -0
@@ -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 947e0701cf7a drivers/xen/fbfront/xenfb.c

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +2 -0
@@ -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;
};

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +12 -0
@@ -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)

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +1 -1
+#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);

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +15 -0
+
+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;

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +79 -8
@@ -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,

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +23 -9
@@ -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)
{

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +9 -0
+     info->resize_dpy = 1;
+    }
+    break;
+  }
+ }
+ mb();   /* ensure we got ring contents */
+ page->in_cons = cons;
+ notify_remote_via_irq(info->irq);
+

return IRQ_HANDLED;
}

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +48 -4
@@ -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,

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +9 -0
@@ -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:

drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000 +2 -0
@@ -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

drivers/xen/fbfront/xenkbd.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenkbd.c Tue Jan 22 21:52:44 2008 +0000 +4 -0
@@ -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

drivers/xen/fbfront/xenkbd.c Thu Jan 24 08:27:06 2008 -0700 renamed from drivers/xen/fbfront/xenkbd.c Tue Jan 22 21:52:44 2008 +0000 +15 -3
@@ -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

include/xen/interface/io/fbif.h Thu Jan 24 08:27:06 2008 -0700 renamed from include/xen/interface/io/fbif.h Tue Jan 22 21:52:44 2008 +0000 +48 -13
@@ -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

include/xen/interface/io/kbdif.h Thu Jan 24 08:27:06 2008 -0700 renamed from include/xen/interface/io/kbdif.h Tue Jan 22 21:52:44 2008 +0000 +4 -0
@@ -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
[email protected]
http://lists.xensource.com/xen-devel

#11 lore raw
Quoted 4 lines · Keir Fraser

Did everyone agree this version is good to go? I'll check it in if Dan and Markus will ack it.

-- Keir

The version you replied to is old. The latest posted version is this:

Message-ID: <[email protected]>
Date: Mon, 04 Feb 2008 11:49:41 -0700
From: Pat Campbell <[email protected]>
Subject: [Xen-devel][RFC]Dynamic modes support for PV xenfb (included)

Find my detailed review in a followup to that. Quick summary: many open questions, and at least one race condition. Nothing structurally dramatic, it just needs work.