Add sys_vumap() kernel call
This new call is a vectored version of sys_umap(). It supports batch lookups, non-contiguous memory, faulting in memory, and basic access checks.
This commit is contained in:
parent
2a395dd8b4
commit
70abb127cc
12 changed files with 216 additions and 3 deletions
|
@ -807,6 +807,7 @@ struct
|
||||||
{ "VIRCOPY", SYS_VIRCOPY },
|
{ "VIRCOPY", SYS_VIRCOPY },
|
||||||
{ "PHYSCOPY", SYS_PHYSCOPY },
|
{ "PHYSCOPY", SYS_PHYSCOPY },
|
||||||
{ "UMAP_REMOTE", SYS_UMAP_REMOTE },
|
{ "UMAP_REMOTE", SYS_UMAP_REMOTE },
|
||||||
|
{ "VUMAP", SYS_VUMAP },
|
||||||
{ "IRQCTL", SYS_IRQCTL },
|
{ "IRQCTL", SYS_IRQCTL },
|
||||||
{ "INT86", SYS_INT86 },
|
{ "INT86", SYS_INT86 },
|
||||||
{ "DEVIO", SYS_DEVIO },
|
{ "DEVIO", SYS_DEVIO },
|
||||||
|
|
|
@ -313,6 +313,7 @@
|
||||||
# define SYS_VIRCOPY (KERNEL_CALL + 15) /* sys_vircopy() */
|
# define SYS_VIRCOPY (KERNEL_CALL + 15) /* sys_vircopy() */
|
||||||
# define SYS_PHYSCOPY (KERNEL_CALL + 16) /* sys_physcopy() */
|
# define SYS_PHYSCOPY (KERNEL_CALL + 16) /* sys_physcopy() */
|
||||||
# define SYS_UMAP_REMOTE (KERNEL_CALL + 17) /* sys_umap_remote() */
|
# 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_IRQCTL (KERNEL_CALL + 19) /* sys_irqctl() */
|
||||||
# define SYS_INT86 (KERNEL_CALL + 20) /* sys_int86() */
|
# define SYS_INT86 (KERNEL_CALL + 20) /* sys_int86() */
|
||||||
|
@ -437,6 +438,16 @@
|
||||||
#define CP_DST_ADDR m5_l2 /* address where data go to */
|
#define CP_DST_ADDR m5_l2 /* address where data go to */
|
||||||
#define CP_NR_BYTES m5_l3 /* number of bytes to copy */
|
#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. */
|
/* Field names for SYS_GETINFO. */
|
||||||
#define I_REQUEST m7_i3 /* what info to get */
|
#define I_REQUEST m7_i3 /* what info to get */
|
||||||
# define GET_KINFO 0 /* get kernel information structure */
|
# define GET_KINFO 0 /* get kernel information structure */
|
||||||
|
|
|
@ -46,9 +46,12 @@
|
||||||
|
|
||||||
#include <sys/null.h> /* NULL Pointer */
|
#include <sys/null.h> /* NULL Pointer */
|
||||||
|
|
||||||
#define SCPVEC_NR 64 /* max # of entries in a SYS_VSAFECOPY* request */
|
#define SCPVEC_NR 64 /* max # of entries in a SYS_VSAFECOPY request */
|
||||||
#define NR_IOREQS 64
|
#define MAPVEC_NR 64 /* max # of entries in a SYS_VUMAP request */
|
||||||
/* maximum number of entries in an iorequest */
|
#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. */
|
/* Message passing constants. */
|
||||||
#define MESS_SIZE (sizeof(message)) /* might need usizeof from FS here */
|
#define MESS_SIZE (sizeof(message)) /* might need usizeof from FS here */
|
||||||
|
|
|
@ -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));
|
vir_bytes bytes, phys_bytes *phys_addr));
|
||||||
_PROTOTYPE(int sys_umap_remote, (endpoint_t proc_ep, endpoint_t grantee,
|
_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));
|
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. */
|
/* Shorthands for sys_getinfo() system call. */
|
||||||
#define sys_getkmessages(dst) sys_getinfo(GET_KMESSAGES, dst, 0,0,0)
|
#define sys_getkmessages(dst) sys_getinfo(GET_KMESSAGES, dst, 0,0,0)
|
||||||
|
|
|
@ -59,6 +59,23 @@ struct vir_cp_req {
|
||||||
phys_bytes count;
|
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 {
|
typedef struct {
|
||||||
vir_bytes iov_addr; /* address of an I/O buffer */
|
vir_bytes iov_addr; /* address of an I/O buffer */
|
||||||
vir_bytes iov_size; /* sizeof an I/O buffer */
|
vir_bytes iov_size; /* sizeof an I/O buffer */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#define USE_PRIVCTL 1 /* system privileges control */
|
#define USE_PRIVCTL 1 /* system privileges control */
|
||||||
#define USE_UMAP 1 /* map virtual to physical address */
|
#define USE_UMAP 1 /* map virtual to physical address */
|
||||||
#define USE_UMAP_REMOTE 1 /* sys_umap on behalf of another process */
|
#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_VIRCOPY 1 /* copy using virtual addressing */
|
||||||
#define USE_PHYSCOPY 1 /* copy using physical addressing */
|
#define USE_PHYSCOPY 1 /* copy using physical addressing */
|
||||||
#define USE_MEMSET 1 /* write char to a given memory area */
|
#define USE_MEMSET 1 /* write char to a given memory area */
|
||||||
|
|
|
@ -224,6 +224,7 @@ PUBLIC void system_init(void)
|
||||||
/* Copying. */
|
/* Copying. */
|
||||||
map(SYS_UMAP, do_umap); /* map virtual to physical address */
|
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_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_VIRCOPY, do_vircopy); /* use pure virtual addressing */
|
||||||
map(SYS_PHYSCOPY, do_copy); /* use physical addressing */
|
map(SYS_PHYSCOPY, do_copy); /* use physical addressing */
|
||||||
map(SYS_SAFECOPYFROM, do_safecopy_from);/* copy with pre-granted permission */
|
map(SYS_SAFECOPYFROM, do_safecopy_from);/* copy with pre-granted permission */
|
||||||
|
|
|
@ -92,6 +92,11 @@ _PROTOTYPE( int do_umap_remote, (struct proc * caller, message *m_ptr) );
|
||||||
#define do_umap_remote NULL
|
#define do_umap_remote NULL
|
||||||
#endif
|
#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) );
|
_PROTOTYPE( int do_memset, (struct proc * caller, message *m_ptr) );
|
||||||
#if ! USE_MEMSET
|
#if ! USE_MEMSET
|
||||||
#define do_memset NULL
|
#define do_memset NULL
|
||||||
|
|
|
@ -21,6 +21,7 @@ SRCS+= \
|
||||||
do_copy.c \
|
do_copy.c \
|
||||||
do_umap.c \
|
do_umap.c \
|
||||||
do_umap_remote.c \
|
do_umap_remote.c \
|
||||||
|
do_vumap.c \
|
||||||
do_memset.c \
|
do_memset.c \
|
||||||
do_setgrant.c \
|
do_setgrant.c \
|
||||||
do_privctl.c \
|
do_privctl.c \
|
||||||
|
|
135
kernel/system/do_vumap.c
Normal file
135
kernel/system/do_vumap.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -109,6 +109,7 @@ SRCS= \
|
||||||
sys_voutw.c \
|
sys_voutw.c \
|
||||||
sys_vsafecopy.c \
|
sys_vsafecopy.c \
|
||||||
sys_vtimer.c \
|
sys_vtimer.c \
|
||||||
|
sys_vumap.c \
|
||||||
taskcall.c \
|
taskcall.c \
|
||||||
tickdelay.c \
|
tickdelay.c \
|
||||||
timers.c \
|
timers.c \
|
||||||
|
|
34
lib/libsys/sys_vumap.c
Normal file
34
lib/libsys/sys_vumap.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue