diff mbox

xen: Add grant reference support to framebuffer/input

Message ID 1299527855-5119-1-git-send-email-dgdegra@tycho.nsa.gov
State New
Headers show

Commit Message

Daniel De Graaf March 7, 2011, 7:57 p.m. UTC
Request and support using grant references in backends for
the keyboard and framebuffer.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
---
 hw/xenfb.c |  103 ++++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 76 insertions(+), 27 deletions(-)

Comments

Stefano Stabellini March 8, 2011, 12:01 p.m. UTC | #1
On Mon, 7 Mar 2011, Daniel De Graaf wrote:
> Request and support using grant references in backends for
> the keyboard and framebuffer.

looks good to me
diff mbox

Patch

diff --git a/hw/xenfb.c b/hw/xenfb.c
index 05c51cc..42a1047 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -61,6 +61,7 @@  struct common {
     struct XenDevice  xendev;  /* must be first */
     void              *page;
     DisplayState      *ds;
+    int               uses_gref;
 };
 
 struct XenInput {
@@ -100,22 +101,26 @@  struct XenFB {
 
 static int common_bind(struct common *c)
 {
-    int mfn;
+    int ref;
 
-    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
-	return -1;
     if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
 	return -1;
+    if (xenstore_read_fe_int(&c->xendev, "page-gref", &ref) == 0) {
+	c->page = xc_gnttab_map_grant_ref(c->xendev.gnttabdev, c->xendev.dom, ref, PROT_READ | PROT_WRITE);
+	c->uses_gref = 1;
+    } else if (xenstore_read_fe_int(&c->xendev, "page-ref", &ref) == 0) {
+	xen_pfn_t pfn = ref;
+	c->page = xc_map_foreign_pages(xen_xc, c->xendev.dom, PROT_READ | PROT_WRITE, &pfn, 1);
+	c->uses_gref = 0;
+    } else
+	return -1;
 
-    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
-				   XC_PAGE_SIZE,
-				   PROT_READ | PROT_WRITE, mfn);
     if (c->page == NULL)
 	return -1;
 
     xen_be_bind_evtchn(&c->xendev);
-    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
-		  mfn, c->xendev.remote_port, c->xendev.local_port);
+    xen_be_printf(&c->xendev, 1, "ring ref %d, remote-port %d, local-port %d\n",
+		  ref, c->xendev.remote_port, c->xendev.local_port);
 
     return 0;
 }
@@ -123,10 +128,12 @@  static int common_bind(struct common *c)
 static void common_unbind(struct common *c)
 {
     xen_be_unbind_evtchn(&c->xendev);
-    if (c->page) {
+    if (c->page && c->uses_gref) {
+	xc_gnttab_munmap(c->xendev.gnttabdev, c->page, 1);
+    } else if (c->page) {
 	munmap(c->page, XC_PAGE_SIZE);
-	c->page = NULL;
     }
+    c->page = NULL;
 }
 
 /* -------------------------------------------------------------------- */
@@ -430,8 +437,6 @@  static int xenfb_map_fb(struct XenFB *xenfb)
     struct xenfb_page *page = xenfb->c.page;
     char *protocol = xenfb->c.xendev.protocol;
     int n_fbdirs;
-    unsigned long *pgmfns = NULL;
-    unsigned long *fbmfns = NULL;
     void *map, *pd;
     int mode, ret = -1;
 
@@ -480,36 +485,72 @@  static int xenfb_map_fb(struct XenFB *xenfb)
 #endif
     }
 
-    if (xenfb->pixels) {
+    if (xenfb->pixels && xenfb->c.uses_gref) {
+	xc_gnttab_munmap(xenfb->c.xendev.gnttabdev, xenfb->pixels, xenfb->fbpages);
+    } else if (xenfb->pixels) {
         munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
-        xenfb->pixels = NULL;
     }
+    xenfb->pixels = NULL;
 
     xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
     n_fbdirs = xenfb->fbpages * mode / 8;
     n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
 
-    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
-    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+    if (xenfb->c.uses_gref) {
+	uint32_t* domids = qemu_mallocz(sizeof(uint32_t)*n_fbdirs);
+	uint32_t* refs = qemu_mallocz(sizeof(uint32_t)*n_fbdirs);
+	int i;
+	for(i=0; i < n_fbdirs; i++)
+	{
+	    domids[i] = xenfb->c.xendev.dom;
+	    refs[i] = (mode == 32) ? ((uint32_t*)pd)[i] : ((uint64_t*)pd)[i];
+	}
+
+	map = xc_gnttab_map_grant_refs(xenfb->c.xendev.gnttabdev,
+	                               n_fbdirs, domids, refs, PROT_READ);
+	qemu_free(domids);
+	qemu_free(refs);
 
-    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
-    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
-			       PROT_READ, pgmfns, n_fbdirs);
-    if (map == NULL)
-	goto out;
-    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
-    munmap(map, n_fbdirs * XC_PAGE_SIZE);
+	if (map == NULL)
+	    goto out;
+
+	domids = qemu_mallocz(sizeof(uint32_t)*xenfb->fbpages);
+	refs = qemu_mallocz(sizeof(uint32_t)*xenfb->fbpages);
+	for(i=0; i < xenfb->fbpages; i++)
+	{
+	    domids[i] = xenfb->c.xendev.dom;
+	    refs[i] = (mode == 32) ? ((uint32_t*)map)[i] : ((uint64_t*)map)[i];
+	}
+
+	xc_gnttab_munmap(xenfb->c.xendev.gnttabdev, map, n_fbdirs);
+	xenfb->pixels = xc_gnttab_map_grant_refs(xenfb->c.xendev.gnttabdev,
+				xenfb->fbpages, domids, refs, PROT_READ);
+	qemu_free(domids);
+	qemu_free(refs);
+    } else {
+	unsigned long *pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
+	xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
+	map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+				   PROT_READ, pgmfns, n_fbdirs);
+	qemu_free(pgmfns);
+
+	if (map == NULL)
+	    goto out;
+
+	unsigned long *fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+	xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
+	munmap(map, n_fbdirs * XC_PAGE_SIZE);
+	xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+					     PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
+	qemu_free(fbmfns);
+    }
 
-    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
-					 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
     if (xenfb->pixels == NULL)
 	goto out;
 
     ret = 0; /* all is fine */
 
 out:
-    qemu_free(pgmfns);
-    qemu_free(fbmfns);
     return ret;
 }
 
@@ -893,6 +934,7 @@  static int fb_init(struct XenDevice *xendev)
 #ifdef XENFB_TYPE_RESIZE
     xenstore_write_be_int(xendev, "feature-resize", 1);
 #endif
+    xenstore_write_be_int(xendev, "feature-grants", 1);
     return 0;
 }
 
@@ -946,6 +988,13 @@  static void fb_disconnect(struct XenDevice *xendev)
 {
     struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
 
+    if (fb->pixels && fb->c.uses_gref) {
+	xc_gnttab_munmap(fb->c.xendev.gnttabdev, fb->pixels, fb->fbpages);
+    } else if (fb->pixels) {
+	// Note: not needed if we are doing the mmap() below
+	// munmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE);
+    }
+
     /*
      * FIXME: qemu can't un-init gfx display (yet?).
      *   Replacing the framebuffer with anonymous shared memory