]> xenbits.xensource.com Git - people/pauldu/linux.git/commitdiff
xen/privcmd: add IOCTL_PRIVCMD_MMAP_RESOURCE
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 28 Jul 2017 10:22:49 +0000 (11:22 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Thu, 10 Aug 2017 15:05:46 +0000 (16:05 +0100)
My recent Xen patch series introduces a new HYPERVISOR_memory_op to
support direct priv-mapping of certain guest resources (such as grant
tables) by a tools domain, rather than having to access such resources
via the guest P2M.

This patch adds the necessary infrastructure to the privcmd driver to
complete that support.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
---
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Juergen Gross <jgross@suse.com>
drivers/xen/privcmd.c
include/uapi/xen/privcmd.h
include/xen/interface/memory.h

index feca75b07fddce01e6e121542d3e0b74d321f85f..545185ff02102ab91fcc3e96ab0eeaa85f41f644 100644 (file)
@@ -33,6 +33,7 @@
 #include <xen/xen.h>
 #include <xen/privcmd.h>
 #include <xen/interface/xen.h>
+#include <xen/interface/memory.h>
 #include <xen/interface/hvm/dm_op.h>
 #include <xen/features.h>
 #include <xen/page.h>
@@ -725,6 +726,97 @@ static long privcmd_ioctl_restrict(struct file *file, void __user *udata)
        return 0;
 }
 
+static long privcmd_ioctl_mmap_resource(struct file *file, void __user *udata)
+{
+       struct privcmd_data *data = file->private_data;
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       struct privcmd_mmap_resource kdata;
+       xen_pfn_t *pfns = NULL;
+       int *errs = NULL;
+       struct xen_mem_acquire_resource xdata;
+       int rc;
+
+       if (copy_from_user(&kdata, udata, sizeof(kdata)))
+               return -EFAULT;
+
+       /* If restriction is in place, check the domid matches */
+       if (data->domid != DOMID_INVALID && data->domid != kdata.dom)
+               return -EPERM;
+
+       down_write(&mm->mmap_sem);
+
+       vma = find_vma(mm, kdata.addr);
+       if (!vma || vma->vm_ops != &privcmd_vm_ops) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       pfns = kcalloc(kdata.num, sizeof(*pfns), GFP_KERNEL);
+       if (!pfns) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       errs = kcalloc(kdata.num, sizeof(*errs), GFP_KERNEL);
+       if (!errs) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       if (xen_feature(XENFEAT_auto_translated_physmap)) {
+               struct page **pages;
+               unsigned int i;
+
+               rc = alloc_empty_pages(vma, kdata.num);
+               if (rc < 0)
+                       goto out;
+
+               pages = vma->vm_private_data;
+               for (i = 0; i < kdata.num; i++)
+                       pfns[i] = page_to_pfn(pages[i]);
+       } else
+               vma->vm_private_data = PRIV_VMA_LOCKED;
+
+       memset(&xdata, 0, sizeof(xdata));
+       xdata.domid = kdata.dom;
+       xdata.type = kdata.type;
+       xdata.id = kdata.id;
+       xdata.frame = kdata.idx;
+       xdata.nr_frames = kdata.num;
+       set_xen_guest_handle(xdata.pfns, pfns);
+
+       xen_preemptible_hcall_begin();
+       rc = HYPERVISOR_memory_op(XENMEM_acquire_resource, &xdata);
+       xen_preemptible_hcall_end();
+
+       if (rc)
+               goto out;
+
+       rc = xen_remap_domain_gfn_array(vma, kdata.addr & PAGE_MASK, pfns,
+                                       kdata.num, errs, vma->vm_page_prot,
+                                       DOMID_SELF, vma->vm_private_data);
+       if (rc == kdata.num) {
+               rc = 0;
+       } else {
+               unsigned int i;
+
+               for (i = 0; i < kdata.num; i++) {
+                       if (errs[i]) {
+                               rc = errs[i];
+                               goto out;
+                       }
+               }
+       }
+
+ out:
+       kfree(errs);
+       kfree(pfns);
+
+       up_write(&mm->mmap_sem);
+       return rc;
+}
+
 static long privcmd_ioctl(struct file *file,
                          unsigned int cmd, unsigned long data)
 {
@@ -756,6 +848,10 @@ static long privcmd_ioctl(struct file *file,
                ret = privcmd_ioctl_restrict(file, udata);
                break;
 
+       case IOCTL_PRIVCMD_MMAP_RESOURCE:
+               ret = privcmd_ioctl_mmap_resource(file, udata);
+               break;
+
        default:
                break;
        }
index 63ee95c9dabb44d5943934c122e65c73a4770b81..c42bd8ca8f5c258f79259e0a62922a069201e83c 100644 (file)
@@ -88,6 +88,15 @@ struct privcmd_dm_op {
        const struct privcmd_dm_op_buf __user *ubufs;
 };
 
+struct privcmd_mmap_resource {
+       domid_t dom;
+       __u32 type;
+       __u32 id;
+       __u32 idx;
+       __u64 num;
+       __u64 addr;
+};
+
 /*
  * @cmd: IOCTL_PRIVCMD_HYPERCALL
  * @arg: &privcmd_hypercall_t
@@ -113,5 +122,7 @@ struct privcmd_dm_op {
        _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op))
 #define IOCTL_PRIVCMD_RESTRICT                                 \
        _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t))
+#define IOCTL_PRIVCMD_MMAP_RESOURCE                            \
+       _IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))
 
 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
index 9aa8988cb340ea6bbefbfbbdad88be127452e3c8..45d3678727f0735e713d934725d42bc8ee26c8d6 100644 (file)
@@ -264,4 +264,19 @@ struct xen_remove_from_physmap {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
 
+#define XENMEM_acquire_resource 28
+struct xen_mem_acquire_resource {
+       domid_t domid;
+       uint16_t type;
+
+#define XENMEM_resource_grant_table 0
+
+       uint32_t id;
+       uint32_t nr_frames;
+       uint64_t frame;
+
+       GUEST_HANDLE(xen_pfn_t) pfns;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_mem_acquire_resource);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */