Split off sys_umap_remote from sys_umap

sys_umap now supports only:
- looking up the physical address of a virtual address in the address space
  of the caller;
- looking up the physical address of a grant for which the caller is the
  grantee.

This is enough for nearly all umap users. The new sys_umap_remote supports
lookups in arbitrary address spaces and grants for arbitrary grantees.
This commit is contained in:
Erik van der Kouwe
2011-06-10 14:28:20 +00:00
parent 25d26d76fd
commit 6e0f3b3bda
14 changed files with 198 additions and 95 deletions

View File

@@ -37,6 +37,7 @@
#define USE_IRQCTL 1 /* set an interrupt policy */
#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_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 */

View File

@@ -222,6 +222,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_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 */

View File

@@ -87,6 +87,11 @@ _PROTOTYPE( int do_umap, (struct proc * caller, message *m_ptr) );
#define do_umap NULL
#endif
_PROTOTYPE( int do_umap_remote, (struct proc * caller, message *m_ptr) );
#if ! USE_UMAP_REMOTE
#define do_umap_remote NULL
#endif
_PROTOTYPE( int do_memset, (struct proc * caller, message *m_ptr) );
#if ! USE_MEMSET
#define do_memset NULL

View File

@@ -20,6 +20,7 @@ SRCS+= \
do_vdevio.c \
do_copy.c \
do_umap.c \
do_umap_remote.c \
do_memset.c \
do_setgrant.c \
do_privctl.c \

105
kernel/system/do_umap.c Normal file → Executable file
View File

@@ -2,11 +2,11 @@
* m_type: SYS_UMAP
*
* The parameters for this kernel call are:
* m5_i1: CP_SRC_PROC_NR (process number)
* m5_i1: CP_SRC_PROC_NR (process number)
* m5_s1: CP_SRC_SPACE (segment where address is: T, D, or S)
* m5_l1: CP_SRC_ADDR (virtual address)
* m5_l2: CP_DST_ADDR (returns physical address)
* m5_l3: CP_NR_BYTES (size of datastructure)
* m5_l1: CP_SRC_ADDR (virtual address)
* m5_l2: CP_DST_ADDR (returns physical address)
* m5_l3: CP_NR_BYTES (size of datastructure)
*/
#include "kernel/system.h"
@@ -15,100 +15,25 @@
#if USE_UMAP
#if ! USE_UMAP_REMOTE
#undef do_umap_remote
#endif
/*==========================================================================*
* do_umap *
*==========================================================================*/
PUBLIC int do_umap(struct proc * caller, message * m_ptr)
{
/* Map virtual address to physical, for non-kernel processes. */
int seg_type = m_ptr->CP_SRC_SPACE & SEGMENT_TYPE;
int seg_index = m_ptr->CP_SRC_SPACE & SEGMENT_INDEX;
vir_bytes offset = m_ptr->CP_SRC_ADDR;
int count = m_ptr->CP_NR_BYTES;
int endpt = (int) m_ptr->CP_SRC_ENDPT;
int proc_nr, r;
int naughty = 0;
phys_bytes phys_addr = 0, lin_addr = 0;
struct proc *targetpr;
/* Verify process number. */
if (endpt == SELF)
proc_nr = _ENDPOINT_P(caller->p_endpoint);
else
if (! isokendpt(endpt, &proc_nr))
return(EINVAL);
targetpr = proc_addr(proc_nr);
/* See which mapping should be made. */
switch(seg_type) {
case LOCAL_SEG:
phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
if(!lin_addr) return EFAULT;
naughty = 1;
break;
case LOCAL_VM_SEG:
if(seg_index == MEM_GRANT) {
vir_bytes newoffset;
endpoint_t newep;
int new_proc_nr;
cp_grant_id_t grant = (cp_grant_id_t) offset;
if(verify_grant(targetpr->p_endpoint, caller->p_endpoint, grant, count,
0, 0, &newoffset, &newep) != OK) {
printf("SYSTEM: do_umap: verify_grant in %s, grant %d, bytes 0x%lx, failed, caller %s\n", targetpr->p_name, offset, count, caller->p_name);
proc_stacktrace(caller);
return EFAULT;
}
if(!isokendpt(newep, &new_proc_nr)) {
printf("SYSTEM: do_umap: isokendpt failed\n");
return EFAULT;
}
/* New lookup. */
offset = newoffset;
targetpr = proc_addr(new_proc_nr);
seg_index = D;
}
if(seg_index == T || seg_index == D || seg_index == S) {
phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
} else {
printf("SYSTEM: bogus seg type 0x%lx\n", seg_index);
return EFAULT;
}
if(!lin_addr) {
printf("SYSTEM:do_umap: umap_local failed\n");
return EFAULT;
}
if(vm_lookup(targetpr, lin_addr, &phys_addr, NULL) != OK) {
printf("SYSTEM:do_umap: vm_lookup failed\n");
return EFAULT;
}
if(phys_addr == 0)
panic("vm_lookup returned zero physical address");
break;
default:
if((r=arch_umap(targetpr, offset, count, seg_type, &lin_addr))
!= OK)
return r;
phys_addr = lin_addr;
}
if(vm_running && !vm_contiguous(targetpr, lin_addr, count)) {
printf("SYSTEM:do_umap: not contiguous\n");
return EFAULT;
}
m_ptr->CP_DST_ADDR = phys_addr;
if(naughty || phys_addr == 0) {
printf("kernel: umap 0x%x done by %d / %s, pc 0x%lx, 0x%lx -> 0x%lx\n",
seg_type, caller->p_endpoint, caller->p_name,
caller->p_reg.pc, offset, phys_addr);
printf("caller stack: ");
proc_stacktrace(caller);
}
return (phys_addr == 0) ? EFAULT: OK;
/* This call is a subset of umap_remote, it allows mapping virtual addresses
* in the caller's address space and grants where the caller is specified as
* grantee; after the security check we simply invoke do_umap_remote
*/
if (seg_index != MEM_GRANT && endpt != SELF) return EPERM;
m_ptr->CP_DST_ENDPT = SELF;
return do_umap_remote(caller, m_ptr);
}
#endif /* USE_UMAP */

View File

@@ -0,0 +1,130 @@
/* The kernel call implemented in this file:
* m_type: SYS_UMAP_REMOTE
*
* The parameters for this kernel call are:
* m5_i1: CP_SRC_PROC_NR (process number)
* m5_s1: CP_SRC_SPACE (segment where address is: T, D, or S)
* m5_l1: CP_SRC_ADDR (virtual address)
* m5_i2: CP_DST_ENDPT (process number of grantee to check access for)
* m5_l2: CP_DST_ADDR (returns physical address)
* m5_l3: CP_NR_BYTES (size of datastructure)
*/
#include "kernel/system.h"
#include <minix/endpoint.h>
#if USE_UMAP || USE_UMAP_REMOTE
#if ! USE_UMAP_REMOTE
#undef do_umap_remote
#endif
/*==========================================================================*
* do_umap_remote *
*==========================================================================*/
PUBLIC int do_umap_remote(struct proc * caller, message * m_ptr)
{
/* Map virtual address to physical, for non-kernel processes. */
int seg_type = m_ptr->CP_SRC_SPACE & SEGMENT_TYPE;
int seg_index = m_ptr->CP_SRC_SPACE & SEGMENT_INDEX;
vir_bytes offset = m_ptr->CP_SRC_ADDR;
int count = m_ptr->CP_NR_BYTES;
int endpt = (int) m_ptr->CP_SRC_ENDPT;
endpoint_t grantee = (endpoint_t) m_ptr->CP_DST_ENDPT;
int proc_nr, proc_nr_grantee, r;
int naughty = 0;
phys_bytes phys_addr = 0, lin_addr = 0;
struct proc *targetpr;
/* Verify process number. */
if (endpt == SELF)
proc_nr = _ENDPOINT_P(caller->p_endpoint);
else
if (! isokendpt(endpt, &proc_nr))
return(EINVAL);
targetpr = proc_addr(proc_nr);
/* Verify grantee endpoint */
if (grantee == SELF) {
grantee = caller->p_endpoint;
} else if (grantee == NONE ||
grantee == ANY ||
seg_index != MEM_GRANT ||
!isokendpt(grantee, &proc_nr_grantee)) {
return EINVAL;
}
/* See which mapping should be made. */
switch(seg_type) {
case LOCAL_SEG:
phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
if(!lin_addr) return EFAULT;
naughty = 1;
break;
case LOCAL_VM_SEG:
if(seg_index == MEM_GRANT) {
vir_bytes newoffset;
endpoint_t newep;
int new_proc_nr;
cp_grant_id_t grant = (cp_grant_id_t) offset;
if(verify_grant(targetpr->p_endpoint, grantee, grant, count,
0, 0, &newoffset, &newep) != OK) {
printf("SYSTEM: do_umap: verify_grant in %s, grant %d, bytes 0x%lx, failed, caller %s\n", targetpr->p_name, offset, count, caller->p_name);
proc_stacktrace(caller);
return EFAULT;
}
if(!isokendpt(newep, &new_proc_nr)) {
printf("SYSTEM: do_umap: isokendpt failed\n");
return EFAULT;
}
/* New lookup. */
offset = newoffset;
targetpr = proc_addr(new_proc_nr);
seg_index = D;
}
if(seg_index == T || seg_index == D || seg_index == S) {
phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
} else {
printf("SYSTEM: bogus seg type 0x%lx\n", seg_index);
return EFAULT;
}
if(!lin_addr) {
printf("SYSTEM:do_umap: umap_local failed\n");
return EFAULT;
}
if(vm_lookup(targetpr, lin_addr, &phys_addr, NULL) != OK) {
printf("SYSTEM:do_umap: vm_lookup failed\n");
return EFAULT;
}
if(phys_addr == 0)
panic("vm_lookup returned zero physical address");
break;
default:
if((r=arch_umap(targetpr, offset, count, seg_type, &lin_addr))
!= OK)
return r;
phys_addr = lin_addr;
}
if(vm_running && !vm_contiguous(targetpr, lin_addr, count)) {
printf("SYSTEM:do_umap: not contiguous\n");
return EFAULT;
}
m_ptr->CP_DST_ADDR = phys_addr;
if(naughty || phys_addr == 0) {
printf("kernel: umap 0x%x done by %d / %s, pc 0x%lx, 0x%lx -> 0x%lx\n",
seg_type, caller->p_endpoint, caller->p_name,
caller->p_reg.pc, offset, phys_addr);
printf("caller stack: ");
proc_stacktrace(caller);
}
return (phys_addr == 0) ? EFAULT: OK;
}
#endif /* USE_UMAP || USE_UMAP_REMOTE */