Add a mmap flag (MAP_32BIT) on 64-bit platforms to request that a mapping use

an address in the first 2GB of the process's address space.  This flag should
have the same semantics as the same flag on Linux.

To facilitate this, add a new parameter to vm_map_find() that specifies an
optional maximum virtual address.  While here, fix several callers of
vm_map_find() to use a VMFS_* constant for the findspace argument instead of
TRUE and FALSE.

Reviewed by:	alc
Approved by:	re (kib)
This commit is contained in:
jhb 2013-09-09 18:11:59 +00:00
parent 2a48fed0b3
commit 04bb6e10cd
25 changed files with 92 additions and 50 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
.\" $FreeBSD$
.\"
.Dd August 16, 2013
.Dd September 9, 2013
.Dt MMAP 2
.Os
.Sh NAME
@ -98,6 +98,12 @@ argument by
.Em or Ns 'ing
the following values:
.Bl -tag -width MAP_PREFAULT_READ
.It Dv MAP_32BIT
Request a region in the first 2GB of the current process's address space.
If a suitable region cannot be found,
.Fn mmap
will fail.
This flag is only available on 64-bit platforms.
.It Dv MAP_ALIGNED Ns Pq Fa n
Align the region on a requested boundary.
If a suitable region cannot be found,
@ -362,6 +368,13 @@ was specified and the
argument was not page aligned, or part of the desired address space
resides out of the valid address space for a user process.
.It Bq Er EINVAL
Both
.Dv MAP_FIXED
and
.Dv MAP_32BIT
were specified and part of the desired address space resides outside
of the first 2GB of user address space.
.It Bq Er EINVAL
The
.Fa len
argument

View File

@ -448,9 +448,8 @@ freebsd32_mmap_partial(struct thread *td, vm_offset_t start, vm_offset_t end,
}
} else {
vm_offset_t addr = trunc_page(start);
rv = vm_map_find(map, 0, 0,
&addr, PAGE_SIZE, FALSE, prot,
VM_PROT_ALL, 0);
rv = vm_map_find(map, NULL, 0, &addr, PAGE_SIZE, 0,
VMFS_NO_SPACE, prot, VM_PROT_ALL, 0);
if (rv != KERN_SUCCESS)
return (EINVAL);
}
@ -542,9 +541,8 @@ freebsd32_mmap(struct thread *td, struct freebsd32_mmap_args *uap)
rv = vm_map_remove(map, start, end);
if (rv != KERN_SUCCESS)
return (EINVAL);
rv = vm_map_find(map, 0, 0,
&start, end - start, FALSE,
prot, VM_PROT_ALL, 0);
rv = vm_map_find(map, NULL, 0, &start, end - start,
0, VMFS_NO_SPACE, prot, VM_PROT_ALL, 0);
if (rv != KERN_SUCCESS)
return (EINVAL);
r.fd = fd;

View File

@ -410,8 +410,8 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
/* get anon user mapping, read+write+execute */
error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
&vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
VM_PROT_ALL, 0);
&vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
goto cleanup;
@ -455,7 +455,8 @@ linux_uselib(struct thread *td, struct linux_uselib_args *args)
/* allocate some 'anon' space */
error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
&vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
&vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL,
VM_PROT_ALL, 0);
if (error)
goto cleanup;
}

View File

@ -140,8 +140,8 @@ exec_svr4_imgact(imgp)
*/
vmaddr = virtual_offset;
error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr,
a_out->a_text + a_out->a_data + bss_size, FALSE,
VM_PROT_ALL, VM_PROT_ALL, 0);
a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
goto fail;
@ -204,7 +204,7 @@ exec_svr4_imgact(imgp)
if (bss_size != 0) {
vmaddr = virtual_offset + a_out->a_text + a_out->a_data;
error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr,
bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
goto fail;
#ifdef DEBUG

View File

@ -1291,7 +1291,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
addr = 0;
vm_object_reference(obj->vm_obj);
DRM_UNLOCK(dev);
rv = vm_map_find(map, obj->vm_obj, args->offset, &addr, args->size,
rv = vm_map_find(map, obj->vm_obj, args->offset, &addr, args->size, 0,
VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE, MAP_INHERIT_SHARE);
if (rv != KERN_SUCCESS) {

View File

@ -128,7 +128,7 @@ load_coff_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset,
if (map_len != 0) {
error = vm_map_find(&vmspace->vm_map, NULL, 0, &map_addr,
map_len, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
map_len, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
return (vm_mmap_to_errno(error));
}
@ -473,7 +473,7 @@ exec_coff_imgact(imgp)
DPRINTF(("imgact: error = %d\n", error));
vm_map_find(&vmspace->vm_map, NULL, 0,
(vm_offset_t *)&hole, PAGE_SIZE, VMFS_NO_SPACE,
(vm_offset_t *)&hole, PAGE_SIZE, 0, VMFS_NO_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
DPRINTF(("IBCS2: start vm_dsize = 0x%x, vm_daddr = 0x%p end = 0x%p\n",
ctob(vmspace->vm_dsize), vmspace->vm_daddr,

View File

@ -139,8 +139,8 @@ exec_linux_imgact(struct image_params *imgp)
*/
vmaddr = virtual_offset;
error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr,
a_out->a_text + a_out->a_data + bss_size, FALSE,
VM_PROT_ALL, VM_PROT_ALL, 0);
a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
goto fail;
@ -204,7 +204,7 @@ exec_linux_imgact(struct image_params *imgp)
if (bss_size != 0) {
vmaddr = virtual_offset + a_out->a_text + a_out->a_data;
error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr,
bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
if (error)
goto fail;
#ifdef DEBUG

View File

@ -169,8 +169,8 @@ ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
* Build the GDT and LDT.
*/
gdt = sv->sv_usrstack;
vm_map_find(&vmspace->vm_map, 0, 0, &gdt, IA32_PAGE_SIZE << 1, 0,
VM_PROT_ALL, VM_PROT_ALL, 0);
vm_map_find(&vmspace->vm_map, NULL, 0, &gdt, IA32_PAGE_SIZE << 1, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0);
ldt = gdt + IA32_PAGE_SIZE;
desc.sd_lolimit = 8*NLDT-1;

View File

@ -417,8 +417,9 @@ __elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
* The mapping is not page aligned. This means we have
* to copy the data. Sigh.
*/
rv = vm_map_find(map, NULL, 0, &start, end - start,
FALSE, prot | VM_PROT_WRITE, VM_PROT_ALL, 0);
rv = vm_map_find(map, NULL, 0, &start, end - start, 0,
VMFS_NO_SPACE, prot | VM_PROT_WRITE, VM_PROT_ALL,
0);
if (rv)
return (rv);
if (object == NULL)

View File

@ -269,12 +269,9 @@ do_aout_hdr(struct imgact_gzip * gz)
*/
vmaddr = gz->virtual_offset + gz->a_out.a_text +
gz->a_out.a_data;
error = vm_map_find(&vmspace->vm_map,
NULL,
0,
&vmaddr,
gz->bss_size,
FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr,
gz->bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL,
0);
if (error) {
gz->where = __LINE__;
return (error);

View File

@ -709,8 +709,8 @@ start_init(void *dummy)
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE,
FALSE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
panic("init: couldn't allocate argument space");
p->p_vmspace->vm_maxsaddr = (caddr_t)addr;
p->p_vmspace->vm_ssize = 1;

View File

@ -891,7 +891,7 @@ link_elf_load_file(linker_class_t cls, const char* filename,
}
ef->address = (caddr_t) vm_map_min(kernel_map);
error = vm_map_find(kernel_map, ef->object, 0,
(vm_offset_t *) &ef->address, mapsize, 1,
(vm_offset_t *) &ef->address, mapsize, 0, VMFS_OPTIMAL_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error != 0) {
vm_object_deallocate(ef->object);

View File

@ -689,7 +689,8 @@ link_elf_load_file(linker_class_t cls, const char *filename,
mapbase = VM_MIN_KERNEL_ADDRESS;
#endif
error = vm_map_find(kernel_map, ef->object, 0, &mapbase,
round_page(mapsize), TRUE, VM_PROT_ALL, VM_PROT_ALL, FALSE);
round_page(mapsize), 0, VMFS_OPTIMAL_SPACE, VM_PROT_ALL,
VM_PROT_ALL, 0);
if (error) {
vm_object_deallocate(ef->object);
ef->object = 0;

View File

@ -524,7 +524,7 @@ pipespace_new(cpipe, size)
buffer = (caddr_t) vm_map_min(pipe_map);
error = vm_map_find(pipe_map, NULL, 0,
(vm_offset_t *) &buffer, size, 1,
(vm_offset_t *) &buffer, size, 0, VMFS_ANY_SPACE,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error != KERN_SUCCESS) {
if ((cpipe->pipe_buffer.buffer == NULL) &&

View File

@ -413,7 +413,7 @@ kern_shmat(td, shmid, shmaddr, shmflg)
vm_object_reference(shmseg->object);
rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object,
0, &attach_va, size, (flags & MAP_FIXED) ? VMFS_NO_SPACE :
0, &attach_va, size, 0, (flags & MAP_FIXED) ? VMFS_NO_SPACE :
VMFS_OPTIMAL_SPACE, prot, prot, MAP_INHERIT_SHARE);
if (rv != KERN_SUCCESS) {
vm_object_deallocate(shmseg->object);

View File

@ -954,7 +954,7 @@ shm_map(struct file *fp, size_t size, off_t offset, void **memp)
ofs = offset & PAGE_MASK;
offset = trunc_page(offset);
size = round_page(size + ofs);
rv = vm_map_find(kernel_map, obj, offset, &kva, size,
rv = vm_map_find(kernel_map, obj, offset, &kva, size, 0,
VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE, 0);
if (rv == KERN_SUCCESS) {

View File

@ -786,7 +786,7 @@ pmap_init(void)
continue;
if (addr < VM_MIN_PROM_ADDRESS || addr > VM_MAX_PROM_ADDRESS)
continue;
result = vm_map_find(kernel_map, NULL, 0, &addr, size,
result = vm_map_find(kernel_map, NULL, 0, &addr, size, 0,
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT);
if (result != KERN_SUCCESS || addr != translations[i].om_start)
panic("pmap_init: vm_map_find");

View File

@ -91,6 +91,9 @@
*/
#define MAP_NOCORE 0x00020000 /* dont include these pages in a coredump */
#define MAP_PREFAULT_READ 0x00040000 /* prefault mapping for reading */
#ifdef __LP64__
#define MAP_32BIT 0x00080000 /* map in the low 2GB of address space */
#endif
/*
* Request specific alignment (n == log2 of the desired alignment).

View File

@ -111,7 +111,7 @@ kva_import(void *unused, vmem_size_t size, int flags, vmem_addr_t *addrp)
int result;
addr = vm_map_min(kernel_map);
result = vm_map_find(kernel_map, NULL, 0, &addr, size,
result = vm_map_find(kernel_map, NULL, 0, &addr, size, 0,
VMFS_SUPER_SPACE, VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT);
if (result != KERN_SUCCESS)
return (ENOMEM);

View File

@ -285,7 +285,7 @@ kmem_suballoc(vm_map_t parent, vm_offset_t *min, vm_offset_t *max,
size = round_page(size);
*min = vm_map_min(parent);
ret = vm_map_find(parent, NULL, 0, min, size, superpage_align ?
ret = vm_map_find(parent, NULL, 0, min, size, 0, superpage_align ?
VMFS_SUPER_SPACE : VMFS_ANY_SPACE, VM_PROT_ALL, VM_PROT_ALL,
MAP_ACC_NO_CHARGE);
if (ret != KERN_SUCCESS)

View File

@ -1432,8 +1432,8 @@ vm_map_fixed(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
int
vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
vm_offset_t *addr, /* IN/OUT */
vm_size_t length, int find_space, vm_prot_t prot,
vm_prot_t max, int cow)
vm_size_t length, vm_offset_t max_addr, int find_space,
vm_prot_t prot, vm_prot_t max, int cow)
{
vm_offset_t alignment, initial_addr, start;
int result;
@ -1452,7 +1452,8 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
vm_map_lock(map);
do {
if (find_space != VMFS_NO_SPACE) {
if (vm_map_findspace(map, start, length, addr)) {
if (vm_map_findspace(map, start, length, addr) ||
(max_addr != 0 && *addr + length > max_addr)) {
vm_map_unlock(map);
if (find_space == VMFS_OPTIMAL_SPACE) {
find_space = VMFS_ANY_SPACE;

View File

@ -366,7 +366,7 @@ boolean_t vm_map_check_protection (vm_map_t, vm_offset_t, vm_offset_t, vm_prot_t
vm_map_t vm_map_create(pmap_t, vm_offset_t, vm_offset_t);
int vm_map_delete(vm_map_t, vm_offset_t, vm_offset_t);
int vm_map_find(vm_map_t, vm_object_t, vm_ooffset_t, vm_offset_t *, vm_size_t,
int, vm_prot_t, vm_prot_t, int);
vm_offset_t, int, vm_prot_t, vm_prot_t, int);
int vm_map_fixed(vm_map_t, vm_object_t, vm_ooffset_t, vm_offset_t, vm_size_t,
vm_prot_t, vm_prot_t, int);
int vm_map_findspace (vm_map_t, vm_offset_t, vm_size_t, vm_offset_t *);

View File

@ -94,10 +94,8 @@ SYSCTL_INT(_vm, OID_AUTO, old_mlock, CTLFLAG_RW | CTLFLAG_TUN, &old_mlock, 0,
"Do not apply RLIMIT_MEMLOCK on mlockall");
TUNABLE_INT("vm.old_mlock", &old_mlock);
#ifndef _SYS_SYSPROTO_H_
struct sbrk_args {
int incr;
};
#ifdef MAP_32BIT
#define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31)
#endif
static int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
@ -107,6 +105,12 @@ static int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
static int vm_mmap_shm(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
int *, struct shmfd *, vm_ooffset_t, vm_object_t *);
#ifndef _SYS_SYSPROTO_H_
struct sbrk_args {
int incr;
};
#endif
/*
* MPSAFE
*/
@ -278,6 +282,18 @@ sys_mmap(td, uap)
return (EINVAL);
if (addr + size < addr)
return (EINVAL);
#ifdef MAP_32BIT
if (flags & MAP_32BIT && addr + size > MAP_32BIT_MAX_ADDR)
return (EINVAL);
} else if (flags & MAP_32BIT) {
/*
* For MAP_32BIT, override the hint if it is too high and
* do not bother moving the mapping past the heap (since
* the heap is usually above 2GB).
*/
if (addr + size > MAP_32BIT_MAX_ADDR)
addr = 0;
#endif
} else {
/*
* XXX for non-fixed mappings where no hint is provided or
@ -1620,8 +1636,11 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot,
MAP_ALIGNMENT_SHIFT);
else
findspace = VMFS_OPTIMAL_SPACE;
rv = vm_map_find(map, object, foff, addr, size, findspace,
prot, maxprot, docow);
rv = vm_map_find(map, object, foff, addr, size,
#ifdef MAP_32BIT
flags & MAP_32BIT ? MAP_32BIT_MAX_ADDR :
#endif
0, findspace, prot, maxprot, docow);
} else
rv = vm_map_fixed(map, object, foff, *addr, size,
prot, maxprot, docow);

View File

@ -497,6 +497,10 @@ egrep "^#[[:space:]]*define[[:space:]]+MAP_[A-Z_]+[[:space:]]+0x[0-9A-Fa-f]+[[:s
++i; \
printf "\tif (!((flags > 0) ^ ((%s) > 0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }'
cat <<_EOF_
#ifdef MAP_32BIT
if (!((flags > 0) ^ ((MAP_32BIT) > 0)))
if_print_or(flags, MAP_32BIT, or);
#endif
align = flags & MAP_ALIGNMENT_MASK;
if (align != 0) {
if (align == MAP_ALIGNED_SUPER)

View File

@ -296,7 +296,11 @@ static struct xlat mmap_flags[] = {
X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
X(MAP_NOCORE) X(MAP_PREFAULT_READ) XEND
X(MAP_NOCORE) X(MAP_PREFAULT_READ)
#ifdef MAP_32BIT
X(MAP_32BIT)
#endif
XEND
};
static struct xlat mprot_flags[] = {