Request and support using grant references in backends for
the Xen kbdmouse and framebuffer devices.

Signed-off-by: Daniel De Graaf <dgde...@tycho.nsa.gov>
---

Changes since v1:
  Fixed gntdev device dependency missing from device flags.

 hw/xenfb.c |  105 ++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 78 insertions(+), 27 deletions(-)

diff --git a/hw/xenfb.c b/hw/xenfb.c
index 05c51cc..d00cbe1 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
@@ -989,6 +1038,7 @@ static void fb_event(struct XenDevice *xendev)
 
 struct XenDevOps xen_kbdmouse_ops = {
     .size       = sizeof(struct XenInput),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .init       = input_init,
     .initialise = input_initialise,
     .connected  = input_connected,
@@ -998,6 +1048,7 @@ struct XenDevOps xen_kbdmouse_ops = {
 
 struct XenDevOps xen_framebuffer_ops = {
     .size       = sizeof(struct XenFB),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
     .init       = fb_init,
     .initialise = fb_initialise,
     .disconnect = fb_disconnect,


Reply via email to