diff options
author | Paul Durrant <paul.durrant@citrix.com> | 2018-05-17 16:35:54 +0100 |
---|---|---|
committer | Stefano Stabellini <sstabellini@kernel.org> | 2018-05-22 11:43:21 -0700 |
commit | 3fe12b8403111021e6eaae3b44d01a34922c176a (patch) | |
tree | de878ccca498265c92af8d1b004c3f12825b24c1 | |
parent | 58560f2ae71b99d3032432a4a8457bb2cb21bce1 (diff) | |
download | qemu-3fe12b8403111021e6eaae3b44d01a34922c176a.zip |
xen_backend: add an emulation of grant copy
Not all Xen environments support the xengnttab_grant_copy() operation.
E.g. where the OS is FreeBSD or Xen is older than 4.8.0.
This patch introduces an emulation of that operation using
xengnttab_map_domain_grant_refs() and memcpy() for those environments.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <sstabellini@kernel.org>
-rw-r--r-- | hw/xen/xen_backend.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 50412d6a09..3c3fc2c6e6 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -146,6 +146,55 @@ void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr, } } +static int compat_copy_grant_refs(struct XenDevice *xendev, + bool to_domain, + XenGrantCopySegment segs[], + unsigned int nr_segs) +{ + uint32_t *refs = g_new(uint32_t, nr_segs); + int prot = to_domain ? PROT_WRITE : PROT_READ; + void *pages; + unsigned int i; + + for (i = 0; i < nr_segs; i++) { + XenGrantCopySegment *seg = &segs[i]; + + refs[i] = to_domain ? + seg->dest.foreign.ref : seg->source.foreign.ref; + } + + pages = xengnttab_map_domain_grant_refs(xendev->gnttabdev, nr_segs, + xen_domid, refs, prot); + if (!pages) { + xen_pv_printf(xendev, 0, + "xengnttab_map_domain_grant_refs failed: %s\n", + strerror(errno)); + g_free(refs); + return -1; + } + + for (i = 0; i < nr_segs; i++) { + XenGrantCopySegment *seg = &segs[i]; + void *page = pages + (i * XC_PAGE_SIZE); + + if (to_domain) { + memcpy(page + seg->dest.foreign.offset, seg->source.virt, + seg->len); + } else { + memcpy(seg->dest.virt, page + seg->source.foreign.offset, + seg->len); + } + } + + if (xengnttab_unmap(xendev->gnttabdev, pages, nr_segs)) { + xen_pv_printf(xendev, 0, "xengnttab_unmap failed: %s\n", + strerror(errno)); + } + + g_free(refs); + return 0; +} + int xen_be_copy_grant_refs(struct XenDevice *xendev, bool to_domain, XenGrantCopySegment segs[], @@ -157,6 +206,10 @@ int xen_be_copy_grant_refs(struct XenDevice *xendev, assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV); + if (!xen_feature_grant_copy) { + return compat_copy_grant_refs(xendev, to_domain, segs, nr_segs); + } + xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); for (i = 0; i < nr_segs; i++) { |