{ "VIRCOPY", SYS_VIRCOPY },
{ "PHYSCOPY", SYS_PHYSCOPY },
{ "UMAP_REMOTE", SYS_UMAP_REMOTE },
+ { "VUMAP", SYS_VUMAP },
{ "IRQCTL", SYS_IRQCTL },
{ "INT86", SYS_INT86 },
{ "DEVIO", SYS_DEVIO },
# 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 */
#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 */
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)
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 */
#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 */
/* 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 */
#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
do_copy.c \
do_umap.c \
do_umap_remote.c \
+ do_vumap.c \
do_memset.c \
do_setgrant.c \
do_privctl.c \
--- /dev/null
+/* 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;
+}
sys_voutw.c \
sys_vsafecopy.c \
sys_vtimer.c \
+ sys_vumap.c \
taskcall.c \
tickdelay.c \
timers.c \
--- /dev/null
+#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;
+}