aboutsummaryrefslogtreecommitdiff
path: root/sys/vm/vm_mmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vm/vm_mmap.c')
-rw-r--r--sys/vm/vm_mmap.c151
1 files changed, 96 insertions, 55 deletions
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index f963e25c8ffd..e6759a756844 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -37,7 +37,7 @@
*
* from: Utah $Hdr: vm_mmap.c 1.3 90/01/21$
* from: @(#)vm_mmap.c 7.5 (Berkeley) 6/28/91
- * $Id: vm_mmap.c,v 1.8 1993/10/16 16:20:39 rgrimes Exp $
+ * $Id: vm_mmap.c,v 1.21 1994/01/31 04:20:26 davidg Exp $
*/
/*
@@ -58,6 +58,10 @@
#include "vm_pager.h"
#include "vm_prot.h"
#include "vm_statistics.h"
+#include "vm_user.h"
+
+static boolean_t vm_map_is_allocated(vm_map_t, vm_offset_t, vm_offset_t,
+ boolean_t);
#ifdef DEBUG
int mmapdebug = 0;
@@ -67,6 +71,7 @@ int mmapdebug = 0;
#endif
/* ARGSUSED */
+int
getpagesize(p, uap, retval)
struct proc *p;
void *uap;
@@ -82,6 +87,7 @@ struct sbrk_args {
};
/* ARGSUSED */
+int
sbrk(p, uap, retval)
struct proc *p;
struct sbrk_args *uap;
@@ -97,6 +103,7 @@ struct sstk_args {
};
/* ARGSUSED */
+int
sstk(p, uap, retval)
struct proc *p;
struct sstk_args *uap;
@@ -116,13 +123,14 @@ struct smmap_args {
off_t pos;
};
+int
smmap(p, uap, retval)
struct proc *p;
register struct smmap_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
- register struct file *fp;
+ register struct file *fp = 0;
struct vnode *vp;
vm_offset_t addr;
vm_size_t size;
@@ -138,6 +146,7 @@ smmap(p, uap, retval)
p->p_pid, uap->addr, uap->len, uap->prot,
uap->flags, uap->fd, uap->pos);
#endif
+
/*
* Make sure one of the sharing types is specified
*/
@@ -149,16 +158,16 @@ smmap(p, uap, retval)
default:
return(EINVAL);
}
+
/*
* Address (if FIXED) must be page aligned.
* Size is implicitly rounded to a page boundary.
*/
addr = (vm_offset_t) uap->addr;
- if ((flags & MAP_FIXED) && (addr & page_mask) || uap->len < 0)
+ if ((flags & MAP_FIXED) && (addr & PAGE_MASK) || uap->len < 0)
return(EINVAL);
size = (vm_size_t) round_page(uap->len);
- if ((uap->flags & MAP_FIXED) && (addr + size > VM_MAXUSER_ADDRESS))
- return(EINVAL);
+
/*
* XXX if no hint provided for a non-fixed mapping place it after
* the end of the largest possible heap.
@@ -168,6 +177,15 @@ smmap(p, uap, retval)
*/
if (addr == 0 && (flags & MAP_FIXED) == 0)
addr = round_page(p->p_vmspace->vm_daddr + MAXDSIZ);
+
+ /*
+ * Check address range for validity
+ */
+ if (addr + size >= VM_MAXUSER_ADDRESS)
+ return(EINVAL);
+ if (addr > addr + size)
+ return(EINVAL);
+
/*
* Mapping file or named anonymous, get fp for validation
*/
@@ -176,6 +194,23 @@ smmap(p, uap, retval)
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
return(EBADF);
}
+
+ /*
+ * Set initial maximum protection
+ */
+ maxprot = VM_PROT_ALL;
+
+ /*
+ * Map protections to MACH style
+ */
+ prot = VM_PROT_NONE;
+ if (uap->prot & PROT_READ)
+ prot |= VM_PROT_READ;
+ if (uap->prot & PROT_WRITE)
+ prot |= VM_PROT_WRITE;
+ if (uap->prot & PROT_EXEC)
+ prot |= VM_PROT_EXECUTE;
+
/*
* If we are mapping a file we need to check various
* file/vnode related things.
@@ -189,45 +224,36 @@ smmap(p, uap, retval)
vp = (struct vnode *)fp->f_data;
if (vp->v_type != VREG && vp->v_type != VCHR)
return(EINVAL);
+
/*
- * Ensure that file protection and desired protection
- * are compatible. Note that we only worry about writability
- * if mapping is shared.
- */
- if ((uap->prot & PROT_READ) && (fp->f_flag & FREAD) == 0 ||
- ((flags & MAP_SHARED) &&
- (uap->prot & PROT_WRITE) && (fp->f_flag & FWRITE) == 0))
- return(EACCES);
- handle = (caddr_t)vp;
- /*
- * PATCH GVR 25-03-93
- * Map protections to MACH style
+ * Set maxprot according to file protection.
+ * If the file is the backing store, enable maxprot write
+ * if the file protection allows. If the file isn't
+ * the backing store, enable writes.
*/
- if(uap->flags & MAP_SHARED) {
- maxprot = VM_PROT_EXECUTE;
- if (fp->f_flag & FREAD)
- maxprot |= VM_PROT_READ;
+ maxprot = VM_PROT_NONE;
+ if (fp->f_flag & FREAD)
+ maxprot |= VM_PROT_READ|VM_PROT_EXECUTE;
+ if (uap->flags & MAP_SHARED) {
if (fp->f_flag & FWRITE)
maxprot |= VM_PROT_WRITE;
- } else
- maxprot = VM_PROT_ALL;
+ } else {
+ maxprot |= VM_PROT_WRITE;
+ }
+
+ /*
+ * Ensure that calculated maximum protection and desired
+ * protection are compatible.
+ */
+ if ((maxprot & prot) != prot)
+ return(EACCES);
+
+ handle = (caddr_t)vp;
} else if (uap->fd != -1) {
- maxprot = VM_PROT_ALL;
handle = (caddr_t)fp;
} else {
- maxprot = VM_PROT_ALL;
handle = NULL;
}
- /*
- * Map protections to MACH style
- */
- prot = VM_PROT_NONE;
- if (uap->prot & PROT_READ)
- prot |= VM_PROT_READ;
- if (uap->prot & PROT_WRITE)
- prot |= VM_PROT_WRITE;
- if (uap->prot & PROT_EXEC)
- prot |= VM_PROT_EXECUTE;
error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot,
flags, handle, (vm_offset_t)uap->pos);
@@ -241,6 +267,7 @@ struct msync_args {
int len;
};
+int
msync(p, uap, retval)
struct proc *p;
struct msync_args *uap;
@@ -259,7 +286,7 @@ msync(p, uap, retval)
printf("msync(%d): addr %x len %x\n",
p->p_pid, uap->addr, uap->len);
#endif
- if (((int)uap->addr & page_mask) || uap->len < 0)
+ if (((int)uap->addr & PAGE_MASK) || uap->len < 0)
return(EINVAL);
addr = oaddr = (vm_offset_t)uap->addr;
osize = (vm_size_t)uap->len;
@@ -315,6 +342,7 @@ struct munmap_args {
int len;
};
+int
munmap(p, uap, retval)
register struct proc *p;
register struct munmap_args *uap;
@@ -330,13 +358,15 @@ munmap(p, uap, retval)
#endif
addr = (vm_offset_t) uap->addr;
- if ((addr & page_mask) || uap->len < 0)
+ if ((addr & PAGE_MASK) || uap->len < 0)
return(EINVAL);
size = (vm_size_t) round_page(uap->len);
if (size == 0)
return(0);
if (addr + size >= VM_MAXUSER_ADDRESS)
return(EINVAL);
+ if (addr >= addr + size)
+ return(EINVAL);
if (!vm_map_is_allocated(&p->p_vmspace->vm_map, addr, addr+size,
FALSE))
return(EINVAL);
@@ -345,8 +375,10 @@ munmap(p, uap, retval)
return(0);
}
+int
munmapfd(p, fd)
register struct proc *p;
+ int fd;
{
#ifdef DEBUG
if (mmapdebug & MDB_FOLLOW)
@@ -357,6 +389,7 @@ munmapfd(p, fd)
* XXX -- should vm_deallocate any regions mapped to this file
*/
p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED;
+ return 0;
}
struct mprotect_args {
@@ -365,6 +398,7 @@ struct mprotect_args {
int prot;
};
+int
mprotect(p, uap, retval)
struct proc *p;
struct mprotect_args *uap;
@@ -381,7 +415,7 @@ mprotect(p, uap, retval)
#endif
addr = (vm_offset_t) uap->addr;
- if ((addr & page_mask) || uap->len < 0)
+ if ((addr & PAGE_MASK) || uap->len < 0)
return(EINVAL);
size = (vm_size_t) uap->len;
/*
@@ -412,6 +446,7 @@ struct madvise_args {
};
/* ARGSUSED */
+int
madvise(p, uap, retval)
struct proc *p;
struct madvise_args *uap;
@@ -429,6 +464,7 @@ struct mincore_args {
};
/* ARGSUSED */
+int
mincore(p, uap, retval)
struct proc *p;
struct mincore_args *uap;
@@ -446,6 +482,7 @@ mincore(p, uap, retval)
* MAP_FILE: a vnode pointer
* MAP_ANON: NULL or a file pointer
*/
+int
vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
register vm_map_t map;
register vm_offset_t *addr;
@@ -459,7 +496,7 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
register vm_pager_t pager;
boolean_t fitit;
vm_object_t object;
- struct vnode *vp;
+ struct vnode *vp = 0;
int type;
int rv = KERN_SUCCESS;
@@ -485,11 +522,11 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
vp = (struct vnode *)handle;
if (vp->v_type == VCHR) {
type = PG_DEVICE;
- handle = (caddr_t)vp;
+ handle = (caddr_t)(u_long)vp->v_rdev;
} else
type = PG_VNODE;
}
- pager = vm_pager_allocate(type, handle, size, prot);
+ pager = vm_pager_allocate(type, handle, size, prot, foff);
if (pager == NULL)
return (type == PG_DEVICE ? EINVAL : ENOMEM);
/*
@@ -512,13 +549,6 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
goto out;
}
/*
- * The object of unnamed anonymous regions was just created
- * find it for pager_cache.
- */
- if (handle == NULL)
- object = vm_object_lookup(pager);
-
- /*
* Don't cache anonymous objects.
* Loses the reference gained by vm_pager_allocate.
*/
@@ -675,17 +705,25 @@ vm_mmap(map, addr, size, prot, maxprot, flags, handle, foff)
* Changed again: indeed set maximum protection based on
* object permissions.
*/
- rv = vm_map_protect(map, *addr, *addr+size, prot, FALSE);
+ /*
+ * We only need to set max_protection in case it's
+ * unequal to its default, which is VM_PROT_DEFAULT.
+ */
+ if (maxprot != VM_PROT_DEFAULT) {
+ rv = vm_map_protect(map, *addr, *addr+size, maxprot, TRUE);
if (rv != KERN_SUCCESS) {
(void) vm_deallocate(map, *addr, size);
goto out;
}
+ }
/*
- * We only need to set max_protection in case it's
- * unequal to its default, which is VM_PROT_DEFAULT.
+ * We only need to set the protection if it is unequal
+ * to the maximum (if it is equal to maxprot, and isn't
+ * the default, then it would have been set above when
+ * maximum prot was set.
*/
- if(maxprot != VM_PROT_DEFAULT) {
- rv = vm_map_protect(map, *addr, *addr+size, maxprot, TRUE);
+ if (prot != maxprot) {
+ rv = vm_map_protect(map, *addr, *addr+size, prot, FALSE);
if (rv != KERN_SUCCESS) {
(void) vm_deallocate(map, *addr, size);
goto out;
@@ -724,6 +762,7 @@ out:
* Given address and size it returns map attributes as well
* as the (locked) object mapped at that location.
*/
+int
vm_region(map, addr, size, prot, max_prot, inheritance, shared, object, objoff)
vm_map_t map;
vm_offset_t *addr; /* IN/OUT */
@@ -799,6 +838,7 @@ vm_region(map, addr, size, prot, max_prot, inheritance, shared, object, objoff)
/*
* Yet another bastard routine.
*/
+int
vm_allocate_with_pager(map, addr, size, fitit, pager, poffset, internal)
register vm_map_t map;
register vm_offset_t *addr;
@@ -826,7 +866,8 @@ vm_allocate_with_pager(map, addr, size, fitit, pager, poffset, internal)
vm_stat.lookups++;
if (object == NULL) {
object = vm_object_allocate(size);
- vm_object_enter(object, pager);
+ if (!internal)
+ vm_object_enter(object, pager);
} else
vm_stat.hits++;
object->internal = internal;
@@ -848,7 +889,7 @@ vm_allocate_with_pager(map, addr, size, fitit, pager, poffset, internal)
*
* start and end should be page aligned.
*/
-boolean_t
+static boolean_t
vm_map_is_allocated(map, start, end, single_entry)
vm_map_t map;
vm_offset_t start, end;