* [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* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-09 21:19 [RFC] Dynamic modes support for PV xenfb (included) Pat Campbell
@ 2008-03-09 21:29 ` Samuel Thibault
2008-03-10 12:36 ` Samuel Thibault
` (2 subsequent siblings)
3 siblings, 0 replies; 29+ messages in thread
From: Samuel Thibault @ 2008-03-09 21:29 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange, Markus Armbruster
Pat Campbell, le Sun 09 Mar 2008 15:19:59 -0600, a écrit :
> 1. In the resize event handler
> Disabled shared memory (Need to fix)
(Note: that's not a problem, we'll fix that after it gets commited)
Samuel
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-09 21:19 [RFC] Dynamic modes support for PV xenfb (included) 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-12 17:04 ` Markus Armbruster
3 siblings, 0 replies; 29+ messages in thread
From: Samuel Thibault @ 2008-03-10 12:36 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange, Markus Armbruster
Pat Campbell, le Sun 09 Mar 2008 15:19:59 -0600, a écrit :
> + dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
Note: in today's tip, there is a 4th parameter which is the stride.
Samuel
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-09 21:19 [RFC] Dynamic modes support for PV xenfb (included) 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
3 siblings, 1 reply; 29+ messages in thread
From: Samuel Thibault @ 2008-03-10 16:16 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange, Markus Armbruster
Pat Campbell, le Sun 09 Mar 2008 15:19:59 -0600, a écrit :
> 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);
Insert if (xenfb->ds->shared_buf) dpy_setdata(xenfb->ds, xenfb->pixels);
just after dpy_colourdepth() and dpy_resize(), and the video buf sharing
will work (so you can replace 0 with xenfb->depth in the colourdepth
call).
> + xenfb_invalidate(xenfb);
> + break;
Samuel
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-10 16:16 ` Samuel Thibault
@ 2008-03-10 16:36 ` Samuel Thibault
0 siblings, 0 replies; 29+ messages in thread
From: Samuel Thibault @ 2008-03-10 16:36 UTC (permalink / raw)
To: Pat Campbell, xen-devel, Markus Armbruster, Daniel P. Berrange
Samuel Thibault, le Mon 10 Mar 2008 16:16:57 +0000, a écrit :
> Pat Campbell, le Sun 09 Mar 2008 15:19:59 -0600, a écrit :
> > 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);
>
> Insert if (xenfb->ds->shared_buf) dpy_setdata(xenfb->ds, xenfb->pixels);
> just after dpy_colourdepth() and dpy_resize(), and the video buf sharing
> will work (so you can replace 0 with xenfb->depth in the colourdepth
> call).
That actually leads me to the the question of an "offset" support in the
resize event; it would actually be very easy: just add xenfb->offset to
xenfb->pixels in the dpy_setdata call, as well as in the BLT macro and
memcpy call in xenfb_guest_copy.
Samuel
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-09 21:19 [RFC] Dynamic modes support for PV xenfb (included) Pat Campbell
` (2 preceding siblings ...)
2008-03-10 16:16 ` Samuel Thibault
@ 2008-03-12 17:04 ` Markus Armbruster
2008-03-13 13:05 ` Pat Campbell
3 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2008-03-12 17:04 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange, Samuel Thibault
Pat Campbell <plc@novell.com> writes:
> 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)
Could you elaborate on this race?
> 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
I like this much better. A couple of questions remain; see comments
inline.
> 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 */
Spelling of compatible.
> + 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",
Spelling of exceeded.
> + 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;
> + }
This isn't quite watertight, but we can fix that later.
> 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;
Context not shown here, but useful below to convince ourselves this is
correct:
if (xenfb_switch_state(&xenfb->kbd, 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.
> */
You still need this wart because you still set the default resolution
in xenkbd_probe(). You later reset it to the real maximum resolution
in xenkbd_backend_changed(), after frontend went to state Connected.
I wonder whether the first one is necessary.
> #ifdef __KERNEL__
> #define XENFB_WIDTH 800
> 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;
I think you can info->dirty = 0 here. Saves an update event.
> + 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) {
Avoidable long lines due to excessive indentation.
> + 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) &&
Ditto.
> + 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;
> +}
How is this synchronized with xenfb_do_resize()?
If that runs on another processor, it could see the new value of
resize_dpy, and old values of var.xres and var.yres.
> +
> 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);
You move xenfb_init_shared_page() down because you initialize it from
fb_info. Okay.
>
> 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;
You set info->fb_info earlier because you need it in
xenfb_init_shared_page(). But it's not yet ready for xenfb_remove()
then, and that's why you need to zap it in the error path. I don't
like this, it's too complex. What about passing it to
xenfb_init_shared_page() as argument instead?
>
> /* 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]);
Suggest space around /
>
> 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:
The combined fb/kbd backend writes width and height right before
entering state Connected for both devices. Therefore, we can read it
here in the kbd frontend after observing the kbd backend transitioning
to Conntected. Okay.
But what about the race work-around? If the backend goes through
InitWait to Connected fast enough, we don't see the InitWait, and we
work around the race with the goto InitWait. But are we guaranteed to
get called a second time for the transition to Connected? If not,
width and height are never read.
Why don't we have to set the parameters on dynamic resolution change?
> 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
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC] Dynamic modes support for PV xenfb (included)
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
0 siblings, 2 replies; 29+ messages in thread
From: Pat Campbell @ 2008-03-13 13:05 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel, Daniel P. Berrange, Samuel Thibault
Markus Armbruster wrote:
> Pat Campbell <plc@novell.com> writes:
>
>
>> 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)
>>
>
> Could you elaborate on this race?
>
>From the command line I suspend the guest
>From a perl script I:
Resume the guest, xm resume <guest-name>
Loop checking for vnc port in xenstore, when found
immediately attach. 9 times out of 10 times the vncviewer will
be at 600,400 instead of the default 800x600
This happens in Xen 3.2 without any of my code changes and before the
recent shared_buf changes. I intend to investigate this further.
>
>> 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
>>
>
> I like this much better. A couple of questions remain; see comments
> inline.
>
>
>> 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 */
>>
>
> Spelling of compatible.
>
Replaced with code suggestion from Samuel.
>
>> + 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",
>>
>
> Spelling of exceeded.
>
>
Fixed that. Spelling was never my strong suite.
>> + 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;
>> + }
>>
>
> This isn't quite watertight, but we can fix that later.
>
>
>> 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;
>>
>
> Context not shown here, but useful below to convince ourselves this is
> correct:
>
> if (xenfb_switch_state(&xenfb->kbd, 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.
>> */
>>
>
> You still need this wart because you still set the default resolution
> in xenkbd_probe(). You later reset it to the real maximum resolution
> in xenkbd_backend_changed(), after frontend went to state Connected.
> I wonder whether the first one is necessary.
>
>
Yes I think so. Handles the case of the new VM running against an older
vnc-xenfb or qemu that does not send a new value.
>> #ifdef __KERNEL__
>> #define XENFB_WIDTH 800
>> 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;
>>
>
> I think you can info->dirty = 0 here. Saves an update event.
>
Added that and then took it back out. Somehow that caused the GUI to
have a terrible delay, minutes, when starting up before you could enter
your user name password. Changing screens work fast enough. Will have
to investigate this later.
>
>> + 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) {
>>
>
> Avoidable long lines due to excessive indentation.
>
Ok, vim auto indent is my defense.
>
>> + 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) &&
>>
>
> Ditto.
>
Ok
>
>> + 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;
>> +}
>>
>
> How is this synchronized with xenfb_do_resize()?
>
> If that runs on another processor, it could see the new value of
> resize_dpy, and old values of var.xres and var.yres.
>
>
By the time xenfb_set_par() is called the values are already in the fb
struct. They are set sometime between the successful xenfb_check_var()
and xenfb_set_par() calls. I can see a possible condition where if we
are doing back to back resizes utilizing multiple procs we could get a
new xres and an old yres.
I will add into xenfb_check_var() the following test:
if ( xenfb_info->resize_dpy)
return -EINVAL;
and move the resize_dpy clear to below the xenfb_do_resize() call
>> +
>> 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);
>>
>
> You move xenfb_init_shared_page() down because you initialize it from
> fb_info. Okay.
>
>
>>
>> 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;
>>
>
>
> You set info->fb_info earlier because you need it in
> xenfb_init_shared_page(). But it's not yet ready for xenfb_remove()
> then, and that's why you need to zap it in the error path. I don't
> like this, it's too complex. What about passing it to
> xenfb_init_shared_page() as argument instead?
>
Ok, changed that.
>
>>
>> /* 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]);
>>
>
> Suggest space around /
>
Ok
>>
>> 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:
>>
>
> The combined fb/kbd backend writes width and height right before
> entering state Connected for both devices. Therefore, we can read it
> here in the kbd frontend after observing the kbd backend transitioning
> to Conntected. Okay.
>
> But what about the race work-around? If the backend goes through
> InitWait to Connected fast enough, we don't see the InitWait, and we
> work around the race with the goto InitWait. But are we guaranteed to
> get called a second time for the transition to Connected? If not,
> width and height are never read.
>
I debated this. Should those parameters be read before the work
around? Qemu xenfb did reordered things, is the work around still
necessary? Should I work around the work around? I never saw that
case during my testing, not to say it still does not happen. I would
like to see if this is still an issue in a larger audience before changing.
> Why don't we have to set the parameters on dynamic resolution change?
>
I debated this. Should those parameters be read before the work
around? Qemu xenfb did reorder things, is the work around still
necessary? Should I work around the work around? I never saw that
case during my testing, not to say it still does not happen. I would
like to see if this is still an issue in a larger audience before changing.
>
>> 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
>>
I will send out a real patch incorporating your suggestions later today.
Thanks
Pat
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-13 13:05 ` Pat Campbell
@ 2008-03-13 19:53 ` Pat Campbell
2008-03-14 16:39 ` Markus Armbruster
1 sibling, 0 replies; 29+ messages in thread
From: Pat Campbell @ 2008-03-13 19:53 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel, Daniel P. Berrange, Samuel Thibault
Hi,
Stripped out a bunch of stuff
Markus Armbruster wrote:
How is this synchronized with xenfb_do_resize()?
>
> If that runs on another processor, it could see the new value of
> resize_dpy, and old values of var.xres and var.yres.
>
>
My suggested fix did not work. My current solution, included in the
upcoming patch post was to remove function xenfb_resize_screen() and
restored xenfb_thread() to it's original state and put a lock around the
event queue. Resize event is now directly sent from xenfb_set_par().
You might want to have a look at that code.
Pat
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-03-13 13:05 ` Pat Campbell
2008-03-13 19:53 ` Pat Campbell
@ 2008-03-14 16:39 ` Markus Armbruster
1 sibling, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2008-03-14 16:39 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange, Samuel Thibault
Pat Campbell <plc@novell.com> writes:
> Markus Armbruster wrote:
>> Pat Campbell <plc@novell.com> writes:
>>
>>
>>> 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)
>>>
>>
>> Could you elaborate on this race?
>>
>>From the command line I suspend the guest
>>From a perl script I:
> Resume the guest, xm resume <guest-name>
> Loop checking for vnc port in xenstore, when found
> immediately attach. 9 times out of 10 times the vncviewer will
> be at 600,400 instead of the default 800x600
>
> This happens in Xen 3.2 without any of my code changes and before the
> recent shared_buf changes. I intend to investigate this further.
Interesting. Please keep us posted.
>>
>>> 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
>>>
>>
>> I like this much better. A couple of questions remain; see comments
>> inline.
>>
>>
>>> diff -r 854b0704962b tools/ioemu/hw/xenfb.c
[...]
>>> 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
[...]
>>> /*
>>> - * 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.
>>> */
>>>
>>
>> You still need this wart because you still set the default resolution
>> in xenkbd_probe(). You later reset it to the real maximum resolution
>> in xenkbd_backend_changed(), after frontend went to state Connected.
>> I wonder whether the first one is necessary.
>>
>>
> Yes I think so. Handles the case of the new VM running against an older
> vnc-xenfb or qemu that does not send a new value.
You're right.
>>> #ifdef __KERNEL__
>>> #define XENFB_WIDTH 800
>>> 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
[...]
>>> @@ -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;
>>>
>>
>> I think you can info->dirty = 0 here. Saves an update event.
>>
> Added that and then took it back out. Somehow that caused the GUI to
> have a terrible delay, minutes, when starting up before you could enter
> your user name password. Changing screens work fast enough. Will have
> to investigate this later.
Weird. It would be good to know what exactly goes wrong there.
>>> + xenfb_do_resize(info);
>>> +}
>>> +
[...]
>>> +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;
>>> +}
>>>
>>
>> How is this synchronized with xenfb_do_resize()?
>>
>> If that runs on another processor, it could see the new value of
>> resize_dpy, and old values of var.xres and var.yres.
>>
>>
> By the time xenfb_set_par() is called the values are already in the fb
> struct. They are set sometime between the successful xenfb_check_var()
> and xenfb_set_par() calls. I can see a possible condition where if we
> are doing back to back resizes utilizing multiple procs we could get a
> new xres and an old yres.
>
> I will add into xenfb_check_var() the following test:
> if ( xenfb_info->resize_dpy)
> return -EINVAL;
> and move the resize_dpy clear to below the xenfb_do_resize() call
Further discussed in another message, will reply there.
[...]
>>> 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:
>>>
>>
>> The combined fb/kbd backend writes width and height right before
>> entering state Connected for both devices. Therefore, we can read it
>> here in the kbd frontend after observing the kbd backend transitioning
>> to Conntected. Okay.
>>
>> But what about the race work-around? If the backend goes through
>> InitWait to Connected fast enough, we don't see the InitWait, and we
>> work around the race with the goto InitWait. But are we guaranteed to
>> get called a second time for the transition to Connected? If not,
>> width and height are never read.
>>
> I debated this. Should those parameters be read before the work
> around? Qemu xenfb did reordered things, is the work around still
> necessary? Should I work around the work around? I never saw that
> case during my testing, not to say it still does not happen. I would
> like to see if this is still an issue in a larger audience before changing.
The work-around is necessary if the backend can go through InitWait to
Connected without synchronizing with the frontend. It actually
synchronizes by waiting for the frontend changing state to
Initialised. I figure the work-around can be removed.
>> Why don't we have to set the parameters on dynamic resolution change?
>>
> I debated this. Should those parameters be read before the work
> around? Qemu xenfb did reorder things, is the work around still
> necessary? Should I work around the work around? I never saw that
> case during my testing, not to say it still does not happen. I would
> like to see if this is still an issue in a larger audience before changing.
Pardon?
[...]
> I will send out a real patch incorporating your suggestions later today.
>
> Thanks
>
> Pat
Got that, working on it.
^ permalink raw reply [flat|nested] 29+ messages in thread
* [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* Re: [RFC]Dynamic modes support for PV xenfb (included)
2008-02-04 18:49 [RFC]Dynamic " Pat Campbell
@ 2008-02-05 9:52 ` Markus Armbruster
2008-02-05 23:38 ` Pat Campbell
0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2008-02-05 9:52 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange
Pat Campbell <plc@novell.com> writes:
> 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!
> Thanks to all that have looked at this never ending RFC and commented.
PVFB took several interations to pass review into xen-unstable. Took
us roughly five months. I'm fairly confident that this won't drag on
for nearly as long.
> Pat
>
>
> diff -r e32fe4703ab6 drivers/xen/fbfront/xenfb.c
> --- a/drivers/xen/fbfront/xenfb.c Tue Jan 29 11:53:33 2008 +0000
> +++ b/drivers/xen/fbfront/xenfb.c Mon Feb 04 11:34:36 2008 -0700
> @@ -28,6 +28,7 @@
> #include <asm/hypervisor.h>
> #include <xen/evtchn.h>
> #include <xen/interface/io/fbif.h>
> +#include <xen/interface/io/kbdif.h>
> #include <xen/interface/io/protocols.h>
> #include <xen/xenbus.h>
> #include <linux/kthread.h>
> @@ -62,6 +63,13 @@ struct xenfb_info
> struct xenfb_page *page;
> unsigned long *mfns;
> int update_wanted; /* XENFB_TYPE_UPDATE wanted */
> + int feature_resize; /* Backend has resize feature */
> + int resize_dpy;
> + int xres, yres; /* current resolution */
Aren't these redundant with fb_info->var.xres and .yres? Whenever the
same thing is stored in multiple places, a little dwarf in the back of
my brain starts worrying about consistency, which I find kind of
distracting...
> + int fb_size; /* fb size in bytes */
Redundant with fb_info->fix.smem_len?
> + int fb_width; /* fb mem width in pixels */
> + int fb_height; /* fb mem height in pixels */
struct fb_var_screeninfo uses width and height for screen dimension in
mm. Hmm. Perhaps use max_xres and max_yres here?
But do we really need these? The only use outside of xenfb_probe() is
in xenfb_check_var(), which could easily use fb_stride instead.
> + int fb_stride; /* fb stride in bytes */
Redundant with fb_info->fix.line_length?
>
> 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)");
As far as I can see, mem never changes. width and height can change,
but never beyond the initial width. Correct?
Perhaps somebody might want to specify a maximum width different from
the initial width. I don't know.
> +
> +#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 */
I appreciate the attempt to explain how you arrived at the pixel
clock, but it's still confusing. And possibly wrong: the pixel clock
seems to be for 1280x1024, while the resolution is 800x600.
> +#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;
Is this variable still needed? I suspect all its uses can easily be
replaced by struct xenfb's fb_size.
>
> 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);
Style nitpick: long line. The parameter names don't buy us much in a
forward declaration.
> +
> +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() */
I'd keep this comment here, and also copy it to xenfb_do_resize().
> - 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;
I'm not sure the stride changes on resize (see below), but it's
probably a good idea to put it in the protocol.
I think you better set event.resize.depth = XENFB_DEPTH here.
> +
> + 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);
Hmm, ugly. See next comment.
> +}
> +
> 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);
> }
Both screen resizes and dirtying don't go to the backend immediately.
Instead, they accumulate in struct xenfb_info (dirty rectangle and
resize_dpy flag) until they get pushed by xenfb_thread().
The way things work, a resize triggers three events:
1. The update event for the dirty rectangle. In theory, the dirty
rectangle could be clean, but I expect it to be quite dirty in
practice, as user space typically redraws everything right after a
resize.
2. The resize event.
3. Another update event, because xenfb_resize_screen() dirties the
whole screen. This event is delayed until the next iteration of
xenfb_thread()'s loop.
I'd rather do it like this: decree that resize events count as whole
screen updates. Make xenfb_resize_screen() clear the dirty rectangle
(optional, saves an update event). Test resize_dpy before dirty.
Also: you access resize_dpy, xres, yres and fb_stride from multiple
threads without synchronization. I fear that's not safe. Don't you
have to protect them with a spinlock, like dirty_lock protects the
dirty rectangle? Could reuse dirty_lock, I guess.
> 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) {
Avoidable long line due to excessive indentation.
> + 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))) {
Ditto.
Please put all var-> terms on the left hand side, and all xenfb_ terms
on the right hand side. My poor little mind finds that easier to
understand than mixing left and right.
> + var->xres_virtual = var->xres;
> + var->yres_virtual = var->yres;
Stupid question: what about var->pixclock? Does one clock fit all, or
does somebody else update it, or should we recompute it?
> + 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;
I'm not sure we're supposed to touch info->fix. Is it necessary? I
can't see fb_stride change on resize.
> + 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;
> }
All right, what do you do here:
> +
> + info->fb_width = info->xres = XENFB_WIDTH;
> + info->fb_height = info->yres = XENFB_HEIGHT;
> + fb_size = XENFB_DEFAULT_FB_LEN;
Start with defaults.
> +
> + if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
If domain config limits videoram...
> + if (val * MB_ >= XENFB_DEFAULT_FB_LEN) {
... and the limit is below the default,
> + video[KPARAM_MEM] = val;
> + fb_size = val * MB_;
then store it in video[KPARAM_MEM].
Note that it will only get used when kernel parameter video supplied
all values (see right below).
> + }
> + }
> +
> + if (video_cnt == KPARAM_CNT && (video[KPARAM_MEM] * MB_) >= XENFB_DEFAULT_FB_LEN) {
If kernel parameter video supplied all values, and the memory value is
above the default,
> + fb_size = video[KPARAM_MEM] * MB_;
then use it instead of the default,
else silently ignore the memory value.
> + if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH/8 < fb_size) {
If kernel parameter video supplied all values, and the width and
height values fit the memory value we actually use,
> + info->fb_width = info->xres = video[KPARAM_WIDTH];
> + info->fb_height = info->yres = video[KPARAM_HEIGHT];
> + }
then use them instead of the defaults,
else silently ignore them.
> + }
Isn't this too complicated?
Why do you ignore memory sizes below the default (both xenstore and
kernel parameters)? I'd trust the system administrator here. If he
asks for a 320x200 rope to hang himself, just give it to him.
Ignoring kernel parameters silently isn't very nice.
I suspect this would be easier if you initialized video[] with the
defaults. Then reduce memory for xenstore's videoram. Then check
width & height against memory, and reduce until they fit.
> +
> + 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;
Still needs a comment :)
> 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]);
Indented one tab too much.
> +
> + 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;
Can't have more than one device. How ugly.
> /*
> * 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) {
Race condition: if this gets executed after xenkbd_probe() read
max_abs_xres, max_abs_yres, but before it set mouse_ptr, the geometry
update gets lost.
I fear you need proper synchronization instead of a hack...
> + 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 */
"future" isn't so helpful. What about "bits per pixel"? If the
backend can deal with that already. If not, I'd comment "reserved for
future use".
> +};
> +
> #define XENFB_OUT_EVENT_SIZE 40
>
> union xenfb_out_event
> {
> uint8_t type;
> struct xenfb_update update;
> + struct xenfb_resize resize;
> char pad[XENFB_OUT_EVENT_SIZE];
> };
>
> @@ -109,21 +125,13 @@ struct xenfb_page
> * Each directory page holds PAGE_SIZE / sizeof(*pd)
> * framebuffer pages, and can thus map up to PAGE_SIZE *
> * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and
> - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory
> - * pages should be enough for a while.
> + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs
> + * 64 bit. 256 directories give enough room for a 512 Meg
> + * framebuffer with a max resolution of 12,800x10,240. Should
> + * be enough for a while with room leftover for expansion.
> */
> - unsigned long pd[2];
> + unsigned long pd[256];
> };
> -
> -/*
> - * Wart: xenkbd needs to know resolution. Put it here until a better
> - * solution is found, but don't leak it to the backend.
> - */
> -#ifdef __KERNEL__
> -#define XENFB_WIDTH 800
> -#define XENFB_HEIGHT 600
> -#define XENFB_DEPTH 32
> -#endif
>
> #endif
>
> diff -r e32fe4703ab6 include/xen/interface/io/kbdif.h
> --- a/include/xen/interface/io/kbdif.h Tue Jan 29 11:53:33 2008 +0000
> +++ b/include/xen/interface/io/kbdif.h Fri Feb 01 11:54:37 2008 -0700
> @@ -119,6 +119,10 @@ struct xenkbd_page
> uint32_t out_cons, out_prod;
> };
>
> +#ifdef __KERNEL__
> +void xenkbd_set_ptr_geometry(int xres, int yres);
> +#endif
> +
> #endif
>
> /*
> diff -r 1b013d10c6d1 tools/ioemu/hw/xenfb.c
> --- a/tools/ioemu/hw/xenfb.c Mon Jan 28 10:37:08 2008 +0000
> +++ b/tools/ioemu/hw/xenfb.c Mon Feb 04 07:30:36 2008 -0700
> @@ -264,6 +264,9 @@ struct xenfb *xenfb_new(int domid, Displ
> xenfb->ds = ds;
> xenfb_device_set_domain(&xenfb->fb, domid);
> xenfb_device_set_domain(&xenfb->kbd, domid);
> +
> + /* Indicate we have the frame buffer resize feature */
> + xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
Did you take care of the synchronization problem I pointed out here:
Subject: Re: [Xen-devel][PATCH][IOEMU] Dynamic modes support for PV xenfb (2 of 2)
From: Markus Armbruster <armbru@redhat.com>
Date: Thu, 10 Jan 2008 11:18:41 +0100
Message-ID: <87ejcqhtku.fsf@pike.pond.sub.org>
http://lists.xensource.com/archives/html/xen-devel/2008-01/msg00229.html
?
Discussion starts at
How's the transmission of feature-resize synchronized? The backend
writes it right when it initializes. The frontend reads it on device
probe. What ensures that the backend completes initialization before
the frontend starts probing?
>
> 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)
The diffs are a bit easier to read if you use tabs like the rest of
the file.
> @@ -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;
Indentation inconsistent with the rest of the file. Please stick to 8
per level.
> + }
> 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
[Copy of include/xen/interface/io/fbif.h we already saw, snipp]
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC]Dynamic modes support for PV xenfb (included)
2008-02-05 9:52 ` Markus Armbruster
@ 2008-02-05 23:38 ` Pat Campbell
2008-02-06 15:49 ` Markus Armbruster
0 siblings, 1 reply; 29+ messages in thread
From: Pat Campbell @ 2008-02-05 23:38 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel, Daniel P. Berrange
Markus Armbruster wrote:
> Pat Campbell <plc@novell.com> writes:
>
cut out a whole bunch to address the need to protect some variables.
>
>
>> +
>> + 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);
>>
>
> Hmm, ugly. See next comment.
>
>
>> +}
>> +
>> 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);
>> }
>>
>
> Both screen resizes and dirtying don't go to the backend immediately.
> Instead, they accumulate in struct xenfb_info (dirty rectangle and
> resize_dpy flag) until they get pushed by xenfb_thread().
>
> The way things work, a resize triggers three events:
>
> 1. The update event for the dirty rectangle. In theory, the dirty
> rectangle could be clean, but I expect it to be quite dirty in
> practice, as user space typically redraws everything right after a
> resize.
>
> 2. The resize event.
>
> 3. Another update event, because xenfb_resize_screen() dirties the
> whole screen. This event is delayed until the next iteration of
> xenfb_thread()'s loop.
>
> I'd rather do it like this: decree that resize events count as whole
> screen updates. Make xenfb_resize_screen() clear the dirty rectangle
> (optional, saves an update event). Test resize_dpy before dirty.
>
> Also: you access resize_dpy, xres, yres and fb_stride from multiple
> threads without synchronization. I fear that's not safe. Don't you
> have to protect them with a spinlock, like dirty_lock protects the
> dirty rectangle? Could reuse dirty_lock, I guess.
>
>
Don't need to protect these three:
fb_stride: Eliminated, now using fb_info->fixed.line_len which is read
only after probe()
xres, yres:
Set in xenfb_set_par(), read only in all other threads.
resize_dpy:
While thinking about this variable it occurred to me that a resize would
invalidate any screen updates that are in the queue. Resize from
xenfb_thread() was done so that I could ensure that the resize did not
get lost due to a queue full situation. So, if I clear the queue,
cons=prod, I can add in the resize event packet directly from
xenfb_set_par() getting rid of resizing from within the thread. Change
would require a new spinlock to protect the queue but would eliminate
resize_dpy.
Setting cons=prod should be safe. Worst case is when a clear occurs
while backend is in the event for loop, loop process events it did not
need to.
xenfb_resize_screen() becomes: (called directly from xenfb_set_par())
spin_lock_irqsave(&info->queue_lock, flags);
info->page->out_cons = info->page->out_prod;
spin_unlock_irqrestore(&info->queue_lock, flags);
xenfb_do_resize(info);
xenfb_refresh(info, 0, 0, info->xres, info->yres);
xenfb_send_event() becomes:
spin_lock_irqsave(&info->queue_lock, flags);
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;
spin_unlock_irqrestore(&info->queue_lock, flags);
Thoughts on this approach?
Pat
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC]Dynamic modes support for PV xenfb (included)
2008-02-05 23:38 ` Pat Campbell
@ 2008-02-06 15:49 ` Markus Armbruster
0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2008-02-06 15:49 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Daniel P. Berrange
Pat Campbell <plc@novell.com> writes:
> Markus Armbruster wrote:
>> Pat Campbell <plc@novell.com> writes:
>>
> cut out a whole bunch to address the need to protect some variables.
>>
>>
>>> +
>>> + 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);
>>>
>>
>> Hmm, ugly. See next comment.
>>
>>
>>> +}
>>> +
>>> 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);
>>> }
>>>
>>
>> Both screen resizes and dirtying don't go to the backend immediately.
>> Instead, they accumulate in struct xenfb_info (dirty rectangle and
>> resize_dpy flag) until they get pushed by xenfb_thread().
>>
>> The way things work, a resize triggers three events:
>>
>> 1. The update event for the dirty rectangle. In theory, the dirty
>> rectangle could be clean, but I expect it to be quite dirty in
>> practice, as user space typically redraws everything right after a
>> resize.
>>
>> 2. The resize event.
>>
>> 3. Another update event, because xenfb_resize_screen() dirties the
>> whole screen. This event is delayed until the next iteration of
>> xenfb_thread()'s loop.
>>
>> I'd rather do it like this: decree that resize events count as whole
>> screen updates. Make xenfb_resize_screen() clear the dirty rectangle
>> (optional, saves an update event). Test resize_dpy before dirty.
>>
>> Also: you access resize_dpy, xres, yres and fb_stride from multiple
>> threads without synchronization. I fear that's not safe. Don't you
>> have to protect them with a spinlock, like dirty_lock protects the
>> dirty rectangle? Could reuse dirty_lock, I guess.
>>
>>
> Don't need to protect these three:
> fb_stride: Eliminated, now using fb_info->fixed.line_len which is read
> only after probe()
> xres, yres:
> Set in xenfb_set_par(), read only in all other threads.
Say one thread does:
xenfb_info->xres = ...
xenfb_info->yres = ...
xenfb_info->resize_dpy = 1;
And another thread does:
if (info->resize_dpy) {
info->resize_dpy = 0;
event.type = XENFB_TYPE_RESIZE;
event.resize.width = info->xres;
event.resize.height = info->yres;
event.resize.stride = info->fb_stride;
You're in trouble on SMP. The assignment to resize_dpy may be visible
on another processor *before* the assignments to xres, yres. In other
words, the second thread can use old values, and the resize gets lost
or bent out of shape.
You need memory barriers to protect against this. The easiest way by
far to get memory barriers right is to use some higher level
synchronization primitive.
> resize_dpy:
> While thinking about this variable it occurred to me that a resize would
> invalidate any screen updates that are in the queue. Resize from
> xenfb_thread() was done so that I could ensure that the resize did not
> get lost due to a queue full situation. So, if I clear the queue,
> cons=prod, I can add in the resize event packet directly from
> xenfb_set_par() getting rid of resizing from within the thread. Change
It's tempting, isn't it?
> would require a new spinlock to protect the queue but would eliminate
> resize_dpy.
>
> Setting cons=prod should be safe. Worst case is when a clear occurs
> while backend is in the event for loop, loop process events it did not
> need to.
>
> xenfb_resize_screen() becomes: (called directly from xenfb_set_par())
> spin_lock_irqsave(&info->queue_lock, flags);
> info->page->out_cons = info->page->out_prod;
> spin_unlock_irqrestore(&info->queue_lock, flags);
> xenfb_do_resize(info);
> xenfb_refresh(info, 0, 0, info->xres, info->yres);
>
> xenfb_send_event() becomes:
> spin_lock_irqsave(&info->queue_lock, flags);
> 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;
> spin_unlock_irqrestore(&info->queue_lock, flags);
>
> Thoughts on this approach?
>
> Pat
The correctness of a lockless ring buffer depends on having *one*
producer put stuff in (here: frontend), and *one* consumer take stuff
out (here: backend), very carefully.
If I understand you correctly, you're proposing to rely on queue_lock
to synchronize within the frontend (mutex xenfb_resize_screen() and
xenfb_send_event()), and argue that neglecting to synchronize frontend
with backend can't do harm.
I fear you are wrong.
Say the producer empties the ring buffer after the consumer determined
that the ring buffer is not empty, and before it is done taking out
the first element. Say that element is in slot #7.
The producer then continues, and puts stuff into the now empty ring
buffer normally. Eventually, it'll reach slot#7.
The consumer may or may not be done is with that element at that time.
We got a race condition.
^ 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)
2008-01-28 0:48 [RFC] Dynamic " Pat Campbell
@ 2008-01-28 8:07 ` Keir Fraser
2008-01-30 9:43 ` Markus Armbruster
` (2 subsequent siblings)
3 siblings, 0 replies; 29+ messages in thread
From: Keir Fraser @ 2008-01-28 8:07 UTC (permalink / raw)
To: Pat Campbell, xen-devel@lists.xensource.com, Markus Armbruster,
Daniel P. Berrange
On 28/1/08 00:48, "Pat Campbell" <plc@novell.com> wrote:
> 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
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-28 0:48 [RFC] Dynamic " 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 20:43 ` Daniel P. Berrange
2008-02-28 10:36 ` Keir Fraser
3 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2008-01-30 9:43 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel@lists.xensource.com, Daniel P. Berrange
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?
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-30 9:43 ` Markus Armbruster
@ 2008-01-30 13:41 ` Pat Campbell
2008-01-30 17:45 ` Markus Armbruster
0 siblings, 1 reply; 29+ messages in thread
From: Pat Campbell @ 2008-01-30 13:41 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel@lists.xensource.com, Daniel P. Berrange
Markus Armbruster wrote:
> 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.
^ permalink raw reply [flat|nested] 29+ messages in thread* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-30 13:41 ` Pat Campbell
@ 2008-01-30 17:45 ` Markus Armbruster
2008-01-30 20:27 ` Pat Campbell
0 siblings, 1 reply; 29+ messages in thread
From: Markus Armbruster @ 2008-01-30 17:45 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel@lists.xensource.com, Daniel P. Berrange
Pat Campbell <plc@novell.com> writes:
> Markus Armbruster wrote:
>> 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.
Understood.
> 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?
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-30 17:45 ` Markus Armbruster
@ 2008-01-30 20:27 ` Pat Campbell
2008-01-31 8:22 ` Gerd Hoffmann
2008-01-31 9:06 ` Markus Armbruster
0 siblings, 2 replies; 29+ messages in thread
From: Pat Campbell @ 2008-01-30 20:27 UTC (permalink / raw)
To: Markus Armbruster; +Cc: xen-devel@lists.xensource.com, Daniel P. Berrange
Markus Armbruster wrote:
> Pat Campbell <plc@novell.com> writes:
>
>
>> Markus Armbruster wrote:
>>
>>> 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.
>>
>
> Understood.
>
>
>> 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.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
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
1 sibling, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2008-01-31 8:22 UTC (permalink / raw)
To: Pat Campbell
Cc: Derek Murray, xen-devel@lists.xensource.com, Daniel P. Berrange,
Markus Armbruster
Pat Campbell wrote:
> Markus Armbruster wrote:
>> 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.
> 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
--
http://kraxel.fedorapeople.org/xenner/
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-31 8:22 ` Gerd Hoffmann
@ 2008-01-31 8:50 ` Markus Armbruster
0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2008-01-31 8:50 UTC (permalink / raw)
To: Gerd Hoffmann
Cc: Derek Murray, Daniel P. Berrange, xen-devel@lists.xensource.com,
Pat Campbell
Gerd Hoffmann <kraxel@redhat.com> writes:
> Pat Campbell wrote:
>> Markus Armbruster wrote:
>>> 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.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-30 20:27 ` Pat Campbell
2008-01-31 8:22 ` Gerd Hoffmann
@ 2008-01-31 9:06 ` Markus Armbruster
1 sibling, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2008-01-31 9:06 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel@lists.xensource.com, Daniel P. Berrange
Pat Campbell <plc@novell.com> writes:
> Markus Armbruster wrote:
[...]
>> 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.
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.
> 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?
[...]
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-28 0:48 [RFC] Dynamic " Pat Campbell
2008-01-28 8:07 ` Keir Fraser
2008-01-30 9:43 ` Markus Armbruster
@ 2008-01-30 20:43 ` Daniel P. Berrange
2008-02-28 10:36 ` Keir Fraser
3 siblings, 0 replies; 29+ messages in thread
From: Daniel P. Berrange @ 2008-01-30 20:43 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel@lists.xensource.com, Markus Armbruster
On Sun, Jan 27, 2008 at 05:48:41PM -0700, Pat Campbell wrote:
> 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 "
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.
> 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.
--
|=- 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 -=|
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [RFC] Dynamic modes support for PV xenfb (included)
2008-01-28 0:48 [RFC] Dynamic " Pat Campbell
` (2 preceding siblings ...)
2008-01-30 20:43 ` Daniel P. Berrange
@ 2008-02-28 10:36 ` Keir Fraser
2008-02-28 11:36 ` Markus Armbruster
3 siblings, 1 reply; 29+ messages in thread
From: Keir Fraser @ 2008-02-28 10:36 UTC (permalink / raw)
To: Pat Campbell, xen-devel@lists.xensource.com, Markus Armbruster,
Daniel P. Berrange
Did everyone agree this version is good to go? I'll check it in if Dan and
Markus will ack it.
-- Keir
On 28/1/08 00:48, "Pat Campbell" <plc@novell.com> wrote:
> 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
> --- 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
>
> /*
> 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
>
> /*
> _______________________________________________
> 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)
2008-02-28 10:36 ` Keir Fraser
@ 2008-02-28 11:36 ` Markus Armbruster
0 siblings, 0 replies; 29+ messages in thread
From: Markus Armbruster @ 2008-02-28 11:36 UTC (permalink / raw)
To: Keir Fraser
Cc: Daniel P. Berrange, xen-devel@lists.xensource.com, Pat Campbell
Keir Fraser <Keir.Fraser@cl.cam.ac.uk> writes:
> 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: <47A75E45.20907@novell.com>
Date: Mon, 04 Feb 2008 11:49:41 -0700
From: Pat Campbell <plc@novell.com>
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.
^ 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
* 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, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2008-01-02 10:51 UTC (permalink / raw)
To: Pat Campbell; +Cc: xen-devel, Mark Williamson
Pat Campbell wrote:
>> I took a quite look through the code and was impressed by how small a patch
>> was actually required.
The linux framebuffer has resize support, so this is easy ;)
Resizing the framebuffer text console using the "fbset" utility should
work too btw.
>> 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?
Easy. You can zap the mapping, then fill it with other pages in the
page fault handler. I think the driver already does that anyway to
track framebuffer page writes (aka screen updates).
> 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.
Backend handshake would be more tricky. You can't release the pages as
long as the backend has them mapped. Otherwise things will go seriously
wrong, especially in case the kernel decides to use the released pages
as page tables.
When you touch these things anyway it you might want switch over to
grant tables (we have resizeable grant tables and a grant table device
for userspace apps now) to allow the backend access to the framebuffer
memory. And make the structs 32/64-bit invariant.
> Absolute mouse positioning needs to know the resolution to scale the
> position properly. Need some new events to alert it of a resolution change.
Just watch xenbus width/height nodes?
> 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.
On the flip side the current scheme (one page full of mfns) limits the
video memory, for larger virtual screens this must be changed anyway.
So maybe just keep the current scheme for 800x600 fixed size? And
require grant tables for the resizable fb? That will make the amount of
backward compatibility code smaller as the resizeable bits are required
in the grant tables code paths only.
cheers,
Gerd
^ 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-03-09 21:19 [RFC] Dynamic modes support for PV xenfb (included) 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
-- strict thread matches above, loose matches on Subject: below --
2008-02-04 18:49 [RFC]Dynamic " Pat Campbell
2008-02-05 9:52 ` Markus Armbruster
2008-02-05 23:38 ` Pat Campbell
2008-02-06 15:49 ` Markus Armbruster
2008-01-28 0:48 [RFC] Dynamic " 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.