]> Zhao Yanbai Git Server - minix.git/commitdiff
Add sys_vumap() kernel call
authorDavid van Moolenbroek <david@minix3.org>
Wed, 21 Mar 2012 22:51:18 +0000 (23:51 +0100)
committerDavid van Moolenbroek <david@minix3.org>
Sat, 24 Mar 2012 18:51:13 +0000 (19:51 +0100)
This new call is a vectored version of sys_umap(). It supports batch
lookups, non-contiguous memory, faulting in memory, and basic access
checks.

12 files changed:
commands/service/parse.c
include/minix/com.h
include/minix/const.h
include/minix/syslib.h
include/minix/type.h
kernel/config.h
kernel/system.c
kernel/system.h
kernel/system/Makefile.inc
kernel/system/do_vumap.c [new file with mode: 0644]
lib/libsys/Makefile
lib/libsys/sys_vumap.c [new file with mode: 0644]

index 82488e7238350ddc4c9506ce70d7e7f9a783979a..048246d3b566f522c1e491fc0b3d0dde9889f268 100644 (file)
@@ -807,6 +807,7 @@ struct
        { "VIRCOPY",            SYS_VIRCOPY },
        { "PHYSCOPY",           SYS_PHYSCOPY },
        { "UMAP_REMOTE",        SYS_UMAP_REMOTE },
+       { "VUMAP",              SYS_VUMAP },
        { "IRQCTL",             SYS_IRQCTL },
        { "INT86",              SYS_INT86 },
        { "DEVIO",              SYS_DEVIO },
index f959d2c644e3140e037d06d3c4ed02700c24148a..76dc34f2344fd90c4ef3a951823c55cb23f2dd08 100644 (file)
 #  define SYS_VIRCOPY    (KERNEL_CALL + 15)    /* sys_vircopy() */
 #  define SYS_PHYSCOPY   (KERNEL_CALL + 16)    /* sys_physcopy() */
 #  define SYS_UMAP_REMOTE (KERNEL_CALL + 17)   /* sys_umap_remote() */
+#  define SYS_VUMAP      (KERNEL_CALL + 18)    /* sys_vumap() */
 
 #  define SYS_IRQCTL     (KERNEL_CALL + 19)    /* sys_irqctl() */
 #  define SYS_INT86      (KERNEL_CALL + 20)    /* sys_int86() */
 #define CP_DST_ADDR    m5_l2   /* address where data go to */
 #define CP_NR_BYTES    m5_l3   /* number of bytes to copy */
 
+/* Field names for SYS_VUMAP. */
+#define VUMAP_ENDPT    m10_i1  /* grant owner, or SELF for local addresses */
+#define VUMAP_VADDR    m10_l1  /* address of virtual (input) vector */
+#define VUMAP_VCOUNT   m10_i2  /* number of elements in virtual vector */
+#define VUMAP_OFFSET   m10_l2  /* offset into first entry of input vector */
+#define VUMAP_ACCESS   m10_i3  /* access requested for input (VUA_ flags) */
+#define VUMAP_PADDR    m10_l3  /* address of physical (output) vector */
+#define VUMAP_PMAX     m10_i4  /* max number of physical vector elements */
+#define VUMAP_PCOUNT   m10_i1  /* upon return: number of elements filled */
+
 /* Field names for SYS_GETINFO. */
 #define I_REQUEST      m7_i3   /* what info to get */
 #   define GET_KINFO      0    /* get kernel information structure */
index 24eb4fa285532eab6e4d9e8aaf02bbb959094d7d..6adddfb9881fed7483dd91435bef6bc69e4e92ef 100644 (file)
 
 #include <sys/null.h>      /* NULL Pointer */
 
-#define SCPVEC_NR        64    /* max # of entries in a SYS_VSAFECOPY* request */
-#define NR_IOREQS        64
-                               /* maximum number of entries in an iorequest */
+#define SCPVEC_NR        64    /* max # of entries in a SYS_VSAFECOPY request */
+#define MAPVEC_NR        64    /* max # of entries in a SYS_VUMAP request */
+#define NR_IOREQS        64    /* maximum number of entries in an iorequest */
+
+#define VUA_READ       0x01    /* for SYS_VUMAP: read access */
+#define VUA_WRITE      0x02    /* for SYS_VUMAP: write access */
 
 /* Message passing constants. */
 #define MESS_SIZE (sizeof(message))    /* might need usizeof from FS here */
index b085a2006a3d60ed0b1d96f224ae6f7b631db505..d670139ac6c96035ef5e32facf3f53b6ead6fb19 100644 (file)
@@ -177,6 +177,9 @@ _PROTOTYPE(int sys_umap_data_fb, (endpoint_t proc_ep, vir_bytes vir_addr,
         vir_bytes bytes, phys_bytes *phys_addr));
 _PROTOTYPE(int sys_umap_remote, (endpoint_t proc_ep, endpoint_t grantee,
        int seg, vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr));
+_PROTOTYPE(int sys_vumap, (endpoint_t endpt, struct vumap_vir *vvec,
+       int vcount, size_t offset, int access, struct vumap_phys *pvec,
+       int *pcount));
 
 /* Shorthands for sys_getinfo() system call. */
 #define sys_getkmessages(dst)  sys_getinfo(GET_KMESSAGES, dst, 0,0,0)
index 2c8c74cdcc33c1034b59e3cfe8937ee99d2c9811..bb038f27ce6e6b46fbddff3ad8c8ca884724f2dd 100644 (file)
@@ -59,6 +59,23 @@ struct vir_cp_req {
   phys_bytes count;
 };
 
+/* Structures for SYS_VUMAP. */
+struct vumap_vir {
+  union {
+       cp_grant_id_t u_grant;  /* grant identifier, for non-SELF endpoint */
+       vir_bytes u_addr;       /* local virtual address, for SELF endpoint */
+  } vv_u;
+  size_t vv_size;              /* size in bytes */
+};
+#define vv_grant       vv_u.u_grant
+#define vv_addr                vv_u.u_addr
+
+struct vumap_phys {
+  phys_bytes vp_addr;          /* physical address */
+  size_t vp_size;              /* size in bytes */
+};
+
+/* I/O vector structures used in protocols between services. */
 typedef struct {
   vir_bytes iov_addr;          /* address of an I/O buffer */
   vir_bytes iov_size;          /* sizeof an I/O buffer */
index d394697fe314f89bab53bfd447db9751a2c3222f..a3dd15219cbfcdef3e7514027906b5ff488f55ca 100644 (file)
@@ -37,6 +37,7 @@
 #define USE_PRIVCTL               1    /* system privileges control */
 #define USE_UMAP                  1    /* map virtual to physical address */
 #define USE_UMAP_REMOTE           1    /* sys_umap on behalf of another process */
+#define USE_VUMAP                 1    /* vectored virtual to physical mapping */
 #define USE_VIRCOPY       1    /* copy using virtual addressing */ 
 #define USE_PHYSCOPY      1    /* copy using physical addressing */
 #define USE_MEMSET        1    /* write char to a given memory area */
index 77b0d2e3293820aa90bbe3d099c67460d8810504..ab18914c860333180abbee397ee2fe7811a85acf 100644 (file)
@@ -224,6 +224,7 @@ PUBLIC void system_init(void)
   /* Copying. */
   map(SYS_UMAP, do_umap);              /* map virtual to physical address */
   map(SYS_UMAP_REMOTE, do_umap_remote);        /* do_umap for non-caller process */
+  map(SYS_VUMAP, do_vumap);            /* vectored virtual to physical map */
   map(SYS_VIRCOPY, do_vircopy);        /* use pure virtual addressing */
   map(SYS_PHYSCOPY, do_copy);          /* use physical addressing */
   map(SYS_SAFECOPYFROM, do_safecopy_from);/* copy with pre-granted permission */
index e69d47a6736f542a6242662585d4803a09899eb5..85240e023c1598df8a631926eed4c239bab6bdab 100644 (file)
@@ -92,6 +92,11 @@ _PROTOTYPE( int do_umap_remote, (struct proc * caller, message *m_ptr) );
 #define do_umap_remote NULL
 #endif
 
+_PROTOTYPE( int do_vumap, (struct proc * caller, message *m_ptr) );
+#if ! USE_VUMAP
+#define do_vumap NULL
+#endif
+
 _PROTOTYPE( int do_memset, (struct proc * caller, message *m_ptr) );
 #if ! USE_MEMSET
 #define do_memset NULL
index ff8a2561365101c92bb7f9cd7f383310871d9acb..4209c9901dcb101e581e4fb898291d8973623f9b 100644 (file)
@@ -21,6 +21,7 @@ SRCS+=        \
        do_copy.c \
        do_umap.c \
        do_umap_remote.c \
+       do_vumap.c \
        do_memset.c \
        do_setgrant.c \
        do_privctl.c \
diff --git a/kernel/system/do_vumap.c b/kernel/system/do_vumap.c
new file mode 100644 (file)
index 0000000..5cdeaa6
--- /dev/null
@@ -0,0 +1,135 @@
+/* The kernel call implemented in this file:
+ *   m_type:   SYS_VUMAP
+ *
+ * The parameters for this kernel call are:
+ *   m10_i1:   VUMAP_ENDPT     (grant owner, or SELF for local addresses)
+ *   m10_l1:   VUMAP_VADDR     (address of virtual (input) vector)
+ *   m10_i2:   VUMAP_VCOUNT    (number of elements in virtual vector)
+ *   m10_l2:   VUMAP_OFFSET    (offset into first entry of input vector)
+ *   m10_i3:   VUMAP_ACCESS    (safecopy access requested for input)
+ *   m10_l3:   VUMAP_PADDR     (address of physical (output) vector)
+ *   m10_i4:   VUMAP_PMAX      (maximum number of physical vector elements)
+ *   m10_i1:   VUMAP_PCOUNT    (upon return: number of elements filled)
+ */
+
+#include "kernel/system.h"
+
+#include <assert.h>
+
+/*===========================================================================*
+ *                             do_vumap                                     *
+ *===========================================================================*/
+PUBLIC int do_vumap(struct proc *caller, message *m_ptr)
+{
+/* Map a vector of grants or local virtual addresses to physical addresses.
+ * Designed to be used by drivers to perform an efficient lookup of physical
+ * addresses for the purpose of direct DMA from/to a remote process.
+ */
+  endpoint_t endpt, source, granter;
+  struct proc *procp;
+  struct vumap_vir vvec[MAPVEC_NR];
+  struct vumap_phys pvec[MAPVEC_NR];
+  vir_bytes vaddr, paddr, vir_addr, lin_addr;
+  phys_bytes phys_addr;
+  int i, r, proc_nr, vcount, pcount, pmax, access;
+  size_t size, chunk, offset;
+
+  endpt = caller->p_endpoint;
+
+  /* Retrieve and check input parameters. */
+  source = m_ptr->VUMAP_ENDPT;
+  vaddr = (vir_bytes) m_ptr->VUMAP_VADDR;
+  vcount = m_ptr->VUMAP_VCOUNT;
+  offset = m_ptr->VUMAP_OFFSET;
+  access = m_ptr->VUMAP_ACCESS;
+  paddr = (vir_bytes) m_ptr->VUMAP_PADDR;
+  pmax = m_ptr->VUMAP_PMAX;
+
+  if (vcount <= 0 || pmax <= 0)
+       return EINVAL;
+
+  if (vcount > MAPVEC_NR) vcount = MAPVEC_NR;
+  if (pmax > MAPVEC_NR) pmax = MAPVEC_NR;
+
+  /* Convert access to safecopy access flags. */
+  switch (access) {
+  case VUA_READ:               access = CPF_READ; break;
+  case VUA_WRITE:              access = CPF_WRITE; break;
+  case VUA_READ|VUA_WRITE:     access = CPF_READ|CPF_WRITE; break;
+  default:                     return EINVAL;
+  }
+
+  /* Copy in the vector of virtual addresses. */
+  size = vcount * sizeof(vvec[0]);
+
+  if (data_copy(endpt, vaddr, KERNEL, (vir_bytes) vvec, size) != OK)
+       return EFAULT;
+
+  pcount = 0;
+
+  /* Go through the input entries, one at a time. Stop early in case the output
+   * vector has filled up.
+   */
+  for (i = 0; i < vcount && pcount < pmax; i++) {
+       size = vvec[i].vv_size;
+       if (size <= offset)
+               return EINVAL;
+       size -= offset;
+
+       if (source != SELF) {
+               r = verify_grant(source, endpt, vvec[i].vv_grant, size, access,
+                       offset, &vir_addr, &granter);
+               if (r != OK)
+                       return r;
+       } else {
+               vir_addr = vvec[i].vv_addr + offset;
+               granter = endpt;
+       }
+
+       okendpt(granter, &proc_nr);
+       procp = proc_addr(proc_nr);
+
+       lin_addr = umap_local(procp, D, vir_addr, size);
+       if (!lin_addr)
+               return EFAULT;
+
+       /* Each virtual range is made up of one or more physical ranges. */
+       while (size > 0 && pcount < pmax) {
+               chunk = vm_lookup_range(procp, lin_addr, &phys_addr, size);
+
+               if (!chunk) {
+                       /* Try to get the memory allocated, unless the memory
+                        * is supposed to be there to be read from.
+                        */
+                       if (access & CPF_READ)
+                               return EFAULT;
+
+                       /* This call may suspend the current call, or return an
+                        * error for a previous invocation.
+                        */
+                       return vm_check_range(caller, procp, lin_addr, size);
+               }
+
+               pvec[pcount].vp_addr = phys_addr;
+               pvec[pcount].vp_size = chunk;
+               pcount++;
+
+               lin_addr += chunk;
+               size -= chunk;
+       }
+
+       offset = 0;
+  }
+
+  /* Copy out the resulting vector of physical addresses. */
+  assert(pcount > 0);
+
+  size = pcount * sizeof(pvec[0]);
+
+  r = data_copy_vmcheck(caller, KERNEL, (vir_bytes) pvec, endpt, paddr, size);
+
+  if (r == OK)
+       m_ptr->VUMAP_PCOUNT = pcount;
+
+  return r;
+}
index e959818e9e0da2c250376d56485709eb83cd6cf6..d644b218b06c712d38d759f994381dcbcf0e7ca7 100644 (file)
@@ -109,6 +109,7 @@ SRCS=  \
        sys_voutw.c \
        sys_vsafecopy.c \
        sys_vtimer.c \
+       sys_vumap.c \
        taskcall.c \
        tickdelay.c \
        timers.c \
diff --git a/lib/libsys/sys_vumap.c b/lib/libsys/sys_vumap.c
new file mode 100644 (file)
index 0000000..2ceaeb7
--- /dev/null
@@ -0,0 +1,34 @@
+#include "syslib.h"
+
+/*===========================================================================*
+ *                             sys_vumap                                    *
+ *===========================================================================*/
+PUBLIC int sys_vumap(
+  endpoint_t endpt,                    /* source process endpoint, or SELF */
+  struct vumap_vir *vvec,              /* virtual (input) vector */
+  int vcount,                          /* number of elements in vvec */
+  size_t offset,                       /* offset into first vvec element */
+  int access,                          /* requested safecopy access flags */
+  struct vumap_phys *pvec,             /* physical (output) vector */
+  int *pcount                          /* (max, returned) nr of els in pvec */
+)
+{
+  message m;
+  int r;
+
+  m.VUMAP_ENDPT = endpt;
+  m.VUMAP_VADDR = (vir_bytes) vvec;
+  m.VUMAP_VCOUNT = vcount;
+  m.VUMAP_OFFSET = offset;
+  m.VUMAP_ACCESS = access;
+  m.VUMAP_PADDR = (vir_bytes) pvec;
+  m.VUMAP_PMAX = *pcount;
+
+  r = _kernel_call(SYS_VUMAP, &m);
+
+  if (r != OK)
+       return r;
+
+  *pcount = m.VUMAP_PCOUNT;
+  return OK;
+}