From: Erik van der Kouwe Date: Fri, 10 Jun 2011 14:28:20 +0000 (+0000) Subject: Split off sys_umap_remote from sys_umap X-Git-Tag: v3.2.0~535 X-Git-Url: http://zhaoyanbai.com/repos/doc/roff.7.html?a=commitdiff_plain;h=6e0f3b3bda539bdb7866151536d1cd70dc3da719;p=minix.git 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. --- diff --git a/commands/service/service.c b/commands/service/service.c index 291132d82..04b4c565d 100644 --- a/commands/service/service.c +++ b/commands/service/service.c @@ -1153,6 +1153,7 @@ struct { "UMAP", SYS_UMAP }, { "VIRCOPY", SYS_VIRCOPY }, { "PHYSCOPY", SYS_PHYSCOPY }, + { "UMAP_REMOTE", SYS_UMAP_REMOTE }, { "IRQCTL", SYS_IRQCTL }, { "INT86", SYS_INT86 }, { "DEVIO", SYS_DEVIO }, diff --git a/common/include/minix/com.h b/common/include/minix/com.h index ef2c1dfd6..1ae66b6fe 100644 --- a/common/include/minix/com.h +++ b/common/include/minix/com.h @@ -334,6 +334,7 @@ # define SYS_UMAP (KERNEL_CALL + 14) /* sys_umap() */ # 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_IRQCTL (KERNEL_CALL + 19) /* sys_irqctl() */ # define SYS_INT86 (KERNEL_CALL + 20) /* sys_int86() */ diff --git a/common/include/minix/syslib.h b/common/include/minix/syslib.h index 96ce031df..c899a51ac 100644 --- a/common/include/minix/syslib.h +++ b/common/include/minix/syslib.h @@ -175,6 +175,8 @@ _PROTOTYPE(int sys_umap, (endpoint_t proc_ep, int seg, vir_bytes vir_addr, vir_bytes bytes, phys_bytes *phys_addr)); _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)); /* Shorthands for sys_getinfo() system call. */ #define sys_getkmessages(dst) sys_getinfo(GET_KMESSAGES, dst, 0,0,0) diff --git a/drivers/amddev/amddev.c b/drivers/amddev/amddev.c index 02c74dbe8..8f9528f24 100644 --- a/drivers/amddev/amddev.c +++ b/drivers/amddev/amddev.c @@ -357,7 +357,7 @@ static int do_add(message *m) size, proc); return EINVAL; } - r= sys_umap(proc, VM_D, (vir_bytes)start, size, &busaddr); + r= sys_umap_remote(proc, SELF, VM_D, (vir_bytes)start, size, &busaddr); if (r != OK) { printf("amddev`do_add: umap failed for 0x%x@0x%x, proc %d\n", @@ -405,7 +405,7 @@ static int do_add4pci(const message *m) printf("amddev`do_add4pci: should check with PCI\n"); - r= sys_umap(proc, VM_D, (vir_bytes)start, size, &busaddr); + r= sys_umap_remote(proc, SELF, VM_D, (vir_bytes)start, size, &busaddr); if (r != OK) { printf( diff --git a/etc/system.conf b/etc/system.conf index 622910a0c..996046603 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -513,7 +513,7 @@ service amddev { pci device 1022/1103; system - UMAP # 14 + UMAP_REMOTE # 17 ; uid 0; }; diff --git a/kernel/config.h b/kernel/config.h index d3a43dfc1..29f54056f 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -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 */ diff --git a/kernel/system.c b/kernel/system.c index d3d83a2d9..e74baa1f6 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -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 */ diff --git a/kernel/system.h b/kernel/system.h index 187e6d026..e34106d55 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -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 diff --git a/kernel/system/Makefile.inc b/kernel/system/Makefile.inc index acde53ca1..34cf87f5a 100644 --- a/kernel/system/Makefile.inc +++ b/kernel/system/Makefile.inc @@ -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 \ diff --git a/kernel/system/do_umap.c b/kernel/system/do_umap.c old mode 100644 new mode 100755 index eb83db7d9..f36d8e717 --- a/kernel/system/do_umap.c +++ b/kernel/system/do_umap.c @@ -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 */ diff --git a/kernel/system/do_umap_remote.c b/kernel/system/do_umap_remote.c new file mode 100644 index 000000000..7410f6a2c --- /dev/null +++ b/kernel/system/do_umap_remote.c @@ -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 + +#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 */ diff --git a/lib/libsys/Makefile b/lib/libsys/Makefile index 94579e0ed..6e239a054 100644 --- a/lib/libsys/Makefile +++ b/lib/libsys/Makefile @@ -97,6 +97,7 @@ SRCS= \ sys_times.c \ sys_trace.c \ sys_umap.c \ + sys_umap_remote.c \ sys_update.c \ sys_vinb.c \ sys_vinl.c \ diff --git a/lib/libsys/sys_umap_remote.c b/lib/libsys/sys_umap_remote.c new file mode 100755 index 000000000..876f2e996 --- /dev/null +++ b/lib/libsys/sys_umap_remote.c @@ -0,0 +1,35 @@ +#include "syslib.h" + +/*===========================================================================* + * sys_umap_remote * + *===========================================================================*/ +PUBLIC int sys_umap_remote(proc_ep, grantee, seg, vir_addr, bytes, phys_addr) +endpoint_t proc_ep; /* process number to do umap for */ +endpoint_t grantee; /* process nr to check as grantee */ +int seg; /* T, D, or S segment */ +vir_bytes vir_addr; /* address in bytes with segment*/ +vir_bytes bytes; /* number of bytes to be copied */ +phys_bytes *phys_addr; /* placeholder for result */ +{ + message m; + int result; + + /* Note about the grantee parameter: + * - Is ignored for non-grant umap calls, but should be SELF to + * pass the sanity check in that case; + * - May be SELF to get the same behaviour as sys_umap, namely that the + * caller must be the grantee; + * - In all other cases, should be a valid endpoint (neither ANY nor NONE). + */ + + m.CP_SRC_ENDPT = proc_ep; + m.CP_DST_ENDPT = grantee; + m.CP_SRC_SPACE = seg; + m.CP_SRC_ADDR = vir_addr; + m.CP_NR_BYTES = bytes; + + result = _kernel_call(SYS_UMAP_REMOTE, &m); + *phys_addr = m.CP_DST_ADDR; + return(result); +} + diff --git a/servers/pm/profile.c b/servers/pm/profile.c index c7e2b06ea..ec916ab2d 100644 --- a/servers/pm/profile.c +++ b/servers/pm/profile.c @@ -97,13 +97,13 @@ int info_size; phys_bytes p; /* Check if supplied pointers point into user process. */ - if ((r = sys_umap(who_e, VM_D, (vir_bytes) m_in.PROF_CTL_PTR, + if ((r = sys_umap_remote(who_e, SELF, VM_D, (vir_bytes) m_in.PROF_CTL_PTR, 1, &p)) != OK) { printf("PM: PROFILE: umap failed for process %d\n", who_e); return r; } - if ((r =sys_umap(who_e, VM_D, (vir_bytes) m_in.PROF_MEM_PTR, + if ((r =sys_umap_remote(who_e, SELF, VM_D, (vir_bytes) m_in.PROF_MEM_PTR, 1, &p)) != OK) { printf("PM: PROFILE: umap failed for process %d\n", who_e); return r;