Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/xen Implement new ioctl, needed by Xen 4.13:



details:   https://anonhg.NetBSD.org/src/rev/b4f8db92fe1d
branches:  trunk
changeset: 933521:b4f8db92fe1d
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Tue May 26 10:11:56 2020 +0000

description:
Implement new ioctl, needed by Xen 4.13:
IOCTL_PRIVCMD_MMAPBATCH_V2
IOCTL_PRIVCMD_MMAP_RESOURCE
IOCTL_GNTDEV_MMAP_GRANT_REF
IOCTL_GNTDEV_ALLOC_GRANT_REF

diffstat:

 sys/arch/xen/include/xenio.h |   85 ++++-
 sys/arch/xen/xen/privcmd.c   |  727 ++++++++++++++++++++++++++++++++++--------
 2 files changed, 665 insertions(+), 147 deletions(-)

diffs (truncated from 942 to 300 lines):

diff -r 56f207003ab6 -r b4f8db92fe1d sys/arch/xen/include/xenio.h
--- a/sys/arch/xen/include/xenio.h      Tue May 26 10:10:31 2020 +0000
+++ b/sys/arch/xen/include/xenio.h      Tue May 26 10:11:56 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xenio.h,v 1.11 2016/07/07 06:55:40 msaitoh Exp $       */
+/*     $NetBSD: xenio.h,v 1.12 2020/05/26 10:11:56 bouyer Exp $        */
 
 /******************************************************************************
  * privcmd.h
@@ -114,9 +114,92 @@
  */
 #define IOCTL_PRIVCMD_INITDOMAIN_EVTCHN \
     _IOR('P', 5, int)
+
 #define IOCTL_PRIVCMD_MMAPBATCH_V2      \
     _IOW('P', 6, privcmd_mmapbatch_v2_t)
 
+/*
+ * @cmd: IOCTL_PRIVCMD_MMAP_RESOURCE
+ * @arg &privcmd_mmap_resource_t
+ * Return: 
+ * map the specified resource at the provided virtual address
+ */ 
+
+typedef struct privcmd_mmap_resource {
+        domid_t dom;
+       uint32_t type;
+       uint32_t id;
+       uint32_t idx; 
+       uint64_t num; 
+       uint64_t addr;
+} privcmd_mmap_resource_t;
+
+#define IOCTL_PRIVCMD_MMAP_RESOURCE      \
+    _IOW('P', 7, privcmd_mmap_resource_t)
+
+/*
+ * @cmd: IOCTL_GNTDEV_MMAP_GRANT_REF
+ * @arg &ioctl_gntdev_mmap_grant_ref
+ * Return: 
+ * map the grant references at the virtual address provided by caller
+ * The grant ref already exists (e.g. comes from a remote domain)
+ */ 
+struct ioctl_gntdev_grant_ref {
+       /* The domain ID of the grant to be mapped. */
+       uint32_t domid;
+       /* The grant reference of the grant to be mapped. */
+       uint32_t ref;
+};
+
+struct ioctl_gntdev_grant_notify {
+       ssize_t offset;
+       uint32_t action;
+       uint32_t event_channel_port;
+};
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+struct ioctl_gntdev_mmap_grant_ref {
+       /* The number of grants to be mapped. */
+       uint32_t count;
+       uint32_t pad;
+       /* The virtual address where they should be mapped */
+       void *va;
+       /* notify action */
+       struct ioctl_gntdev_grant_notify notify;
+       /* Array of grant references, of size @count. */
+       struct ioctl_gntdev_grant_ref *refs;
+};
+
+#define IOCTL_GNTDEV_MMAP_GRANT_REF \
+    _IOW('P', 8, struct ioctl_gntdev_mmap_grant_ref)
+
+/*
+ * @cmd: IOCTL_GNTDEV_ALLOC_GRANT_REF
+ * @arg &ioctl_gntdev_alloc_grant_ref
+ * Return: 
+ * Allocate local memory and grant it to a remote domain.
+ * local memory is mmaped at the virtual address provided by caller
+ */ 
+
+struct ioctl_gntdev_alloc_grant_ref {
+       /* IN parameters */ 
+       uint16_t domid;
+       uint16_t flags;
+       uint32_t count;
+       void *va;
+       /* notify action */
+       struct ioctl_gntdev_grant_notify notify;
+       /* Variable OUT parameter */  
+       uint32_t *gref_ids; 
+};
+
+#define IOCTL_GNTDEV_ALLOC_GRANT_REF \
+    _IOW('P', 9, struct ioctl_gntdev_alloc_grant_ref)
+
+#define GNTDEV_ALLOC_FLAG_WRITABLE 0x01
+
+
 /* Interface to /dev/xenevt */
 /* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
 #define EVTCHN_RESET  _IO('E', 1)
diff -r 56f207003ab6 -r b4f8db92fe1d sys/arch/xen/xen/privcmd.c
--- a/sys/arch/xen/xen/privcmd.c        Tue May 26 10:10:31 2020 +0000
+++ b/sys/arch/xen/xen/privcmd.c        Tue May 26 10:11:56 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: privcmd.c,v 1.57 2020/05/05 17:02:01 bouyer Exp $ */
+/* $NetBSD: privcmd.c,v 1.58 2020/05/26 10:11:56 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2004 Christian Limpach.
@@ -27,7 +27,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.57 2020/05/05 17:02:01 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: privcmd.c,v 1.58 2020/05/26 10:11:56 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -47,29 +47,68 @@
 #include <xen/hypervisor.h>
 #include <xen/xen.h>
 #include <xen/xenio.h>
+#include <xen/granttables.h>
 
 #define        PRIVCMD_MODE    (S_IRUSR)
 
 /* Magic value is used to mark invalid pages.
  * This must be a value within the page-offset.
  * Page-aligned values including 0x0 are used by the guest.
- */ 
+ */
 #define INVALID_PAGE   0xfff
 
+typedef enum _privcmd_type {
+       PTYPE_PRIVCMD,
+       PTYPE_GNTDEV_REF,
+       PTYPE_GNTDEV_ALLOC
+} privcmd_type;
+
+struct privcmd_object_privcmd {
+        paddr_t *maddr; /* array of machine address to map */
+        int     domid;
+        bool    no_translate;
+};
+
+struct privcmd_object_gntref {
+        struct ioctl_gntdev_grant_notify notify;
+       struct gnttab_map_grant_ref ops[1]; /* variable length */
+};
+
+struct privcmd_object_gntalloc {
+        vaddr_t        gntva;  /* granted area mapped in kernel */
+        uint16_t domid;
+        uint16_t flags;
+        struct ioctl_gntdev_grant_notify notify;
+       uint32_t gref_ids[1]; /* variable length */
+};
+
 struct privcmd_object {
        struct uvm_object uobj;
-       paddr_t *maddr; /* array of machine address to map */
+       privcmd_type type;
        int     npages;
-       int     domid;
+       union {
+               struct privcmd_object_privcmd pc;
+               struct privcmd_object_gntref gr;
+               struct privcmd_object_gntalloc ga;
+       } u;
 };
 
+#define PGO_GNTREF_LEN(count) \
+    (sizeof(struct privcmd_object) + \
+       sizeof(struct gnttab_map_grant_ref) * ((count) - 1))
+
+#define PGO_GNTA_LEN(count) \
+    (sizeof(struct privcmd_object) + \
+       sizeof(uint32_t) * ((count) - 1))
+
 int privcmd_nobjects = 0;
 
 static void privpgop_reference(struct uvm_object *);
 static void privpgop_detach(struct uvm_object *);
 static int privpgop_fault(struct uvm_faultinfo *, vaddr_t , struct vm_page **,
-                        int, int, vm_prot_t, int);
-static int privcmd_map_obj(struct vm_map *, vaddr_t, paddr_t *, int, int);
+                         int, int, vm_prot_t, int);
+static int privcmd_map_obj(struct vm_map *, vaddr_t,
+                          struct privcmd_object *, vm_prot_t);
 
 
 static int
@@ -252,6 +291,414 @@
        }
 }
 
+static vm_prot_t
+privcmd_get_map_prot(struct vm_map *map, vaddr_t start, off_t size)
+{
+       vm_prot_t prot;
+
+       vm_map_lock_read(map);
+       /* get protections. This also check for validity of mapping */
+       if (uvm_map_checkprot(map, start, start + size - 1, VM_PROT_WRITE))
+               prot = VM_PROT_READ | VM_PROT_WRITE;
+       else if (uvm_map_checkprot(map, start, start + size - 1, VM_PROT_READ))
+               prot = VM_PROT_READ;
+       else {
+               printf("privcmd_get_map_prot 0x%lx -> 0x%lx "
+                   "failed\n",
+                   start, (unsigned long)(start + size - 1));
+               prot = UVM_PROT_NONE;
+       }
+       vm_map_unlock_read(map);
+       return prot;
+}
+
+static int
+privcmd_mmap(struct vop_ioctl_args *ap)
+{
+       int i, j;
+       privcmd_mmap_t *mcmd = ap->a_data;
+       privcmd_mmap_entry_t mentry;
+       vaddr_t va;
+       paddr_t ma;
+       struct vm_map *vmm = &curlwp->l_proc->p_vmspace->vm_map;
+       paddr_t *maddr;
+       struct privcmd_object *obj;
+       vm_prot_t prot;
+       int error;
+
+       for (i = 0; i < mcmd->num; i++) {
+               error = copyin(&mcmd->entry[i], &mentry, sizeof(mentry));
+               if (error)
+                       return EINVAL;
+               if (mentry.npages == 0)
+                       return EINVAL;
+               if (mentry.va > VM_MAXUSER_ADDRESS)
+                       return EINVAL;
+               va = mentry.va & ~PAGE_MASK;
+               prot = privcmd_get_map_prot(vmm, va, mentry.npages * PAGE_SIZE);
+               if (prot == UVM_PROT_NONE)
+                       return EINVAL;
+               maddr = kmem_alloc(sizeof(paddr_t) * mentry.npages,
+                   KM_SLEEP);
+               ma = ((paddr_t)mentry.mfn) <<  PGSHIFT;
+               for (j = 0; j < mentry.npages; j++) {
+                       maddr[j] = ma;
+                       ma += PAGE_SIZE;
+               }
+               obj = kmem_alloc(sizeof(*obj), KM_SLEEP);
+               obj->type = PTYPE_PRIVCMD;
+               obj->u.pc.maddr = maddr;
+               obj->u.pc.no_translate = false;
+               obj->npages = mentry.npages;
+               obj->u.pc.domid = mcmd->dom;
+               error  = privcmd_map_obj(vmm, va, obj, prot);
+               if (error)
+                       return error;
+       }
+       return 0;
+}
+
+static int
+privcmd_mmapbatch(struct vop_ioctl_args *ap)
+{
+       int i;
+       privcmd_mmapbatch_t* pmb = ap->a_data;
+       vaddr_t va0;
+       u_long mfn;
+       paddr_t ma;
+       struct vm_map *vmm;
+       vaddr_t trymap;
+       paddr_t *maddr;
+       struct privcmd_object *obj;
+       vm_prot_t prot;
+       int error;
+
+       vmm = &curlwp->l_proc->p_vmspace->vm_map;
+       va0 = pmb->addr & ~PAGE_MASK;
+
+       if (pmb->num == 0)
+               return EINVAL;
+       if (va0 > VM_MAXUSER_ADDRESS)
+               return EINVAL;
+       if (((VM_MAXUSER_ADDRESS - va0) >> PGSHIFT) < pmb->num)
+               return EINVAL;
+
+       prot = privcmd_get_map_prot(vmm, va0, PAGE_SIZE);
+       if (prot == UVM_PROT_NONE)
+               return EINVAL;
+       
+       maddr = kmem_alloc(sizeof(paddr_t) * pmb->num, KM_SLEEP);
+       /* get a page of KVA to check mappins */
+       trymap = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE,
+           UVM_KMF_VAONLY);
+       if (trymap == 0) {
+               kmem_free(maddr, sizeof(paddr_t) * pmb->num);



Home | Main Index | Thread Index | Old Index