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,