* Added <sys/mman.h> header. It declares only mmap() and munmap() yet
and defines the macros needed by them.
* Renamed syscall sys_vm_map_file() to _kern_map_file() and changed the
path to an FD parameter. Changed vm_map_file() accordingly and
adjusted the kernel ELF loader and the runtime loader.
* Added syscall _kern_unmap_memory().
* Added bool unmapAddressRange parameter to vm_create_anonymous_area()
and map_backing_store(). If true and the address specification is
B_EXACT_ADDRESS, all areas in the specified address range will be
deleted (unless an area is covered only partially).
* Introduced B_SHARED_AREA flag, which is set on areas that have been
created by {vm,_user}_map_file() with REGION_NO_PRIVATE_MAP. When
fork()ing those areas won't be copied CoW, but rather be cloned. This
is needed for mmap() MAP_SHARED.
* {vm,_user}_map_file() also accept an FD argument < 0, in which case an
anonymous area is created.
* Implemented mmap() and munmap(). Currently there's the restriction
that we can't partially unmap areas. Otherwise the functions should be
rather compliant. We also support the non-POSIX extension
MAP_ANONYMOUS.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24964 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2008, Haiku Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SYS_MMAN_H
|
||||
#define _SYS_MMAN_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
// memory protection for mmap() and others
|
||||
#define PROT_READ 0x01
|
||||
#define PROT_WRITE 0x02
|
||||
#define PROT_EXEC 0x04
|
||||
#define PROT_NONE 0x00
|
||||
|
||||
// mmap() flags
|
||||
#define MAP_SHARED 0x01 /* changes are seen by others */
|
||||
#define MAP_PRIVATE 0x02 /* changes are only seen by caller */
|
||||
#define MAP_FIXED 0x04 /* require mapping to specified addr */
|
||||
#define MAP_ANONYMOUS 0x08 /* no underlying object */
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
// mmap() error return code
|
||||
#define MAP_FAILED ((void*)-1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern void* mmap(void* address, size_t length, int protection, int flags,
|
||||
int fd, off_t offset);
|
||||
extern int munmap(void* address, size_t length);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // _SYS_MMAN_H
|
||||
@@ -296,8 +296,10 @@ extern area_id _kern_clone_area(const char *name, void **_address, uint32 addre
|
||||
extern status_t _kern_reserve_heap_address_range(addr_t* _address, uint32 addressSpec,
|
||||
addr_t size);
|
||||
|
||||
area_id sys_vm_map_file(const char *name, void **address, int addr_type,
|
||||
addr_t size, int lock, int mapping, const char *path, off_t offset);
|
||||
extern area_id _kern_map_file(const char *name, void **address,
|
||||
int addressSpec, addr_t size, int protection,
|
||||
int mapping, int fd, off_t offset);
|
||||
extern status_t _kern_unmap_memory(void *address, addr_t size);
|
||||
|
||||
/* kernel port functions */
|
||||
extern port_id _kern_create_port(int32 queue_length, const char *name);
|
||||
|
||||
@@ -45,14 +45,17 @@ struct vnode;
|
||||
| B_KERNEL_STACK_AREA)
|
||||
|
||||
#define B_OVERCOMMITTING_AREA 0x1000
|
||||
// ToDo: this is not really a protection flag, but since the "protection"
|
||||
#define B_SHARED_AREA 0x2000
|
||||
// TODO: These aren't really a protection flags, but since the "protection"
|
||||
// field is the only flag field, we currently use it for this.
|
||||
// A cleaner approach would be appreciated - maybe just an official generic
|
||||
// flags region in the protection field.
|
||||
|
||||
|
||||
#define B_USER_AREA_FLAGS (B_USER_PROTECTION)
|
||||
#define B_KERNEL_AREA_FLAGS \
|
||||
(B_KERNEL_PROTECTION | B_USER_CLONEABLE_AREA | B_OVERCOMMITTING_AREA)
|
||||
(B_KERNEL_PROTECTION | B_USER_CLONEABLE_AREA | B_OVERCOMMITTING_AREA \
|
||||
| B_SHARED_AREA)
|
||||
|
||||
// flags for vm_get_physical_page()
|
||||
enum {
|
||||
@@ -106,12 +109,13 @@ status_t vm_unreserve_address_range(team_id team, void *address, addr_t size);
|
||||
status_t vm_reserve_address_range(team_id team, void **_address,
|
||||
uint32 addressSpec, addr_t size, uint32 flags);
|
||||
area_id vm_create_anonymous_area(team_id team, const char *name, void **address,
|
||||
uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection);
|
||||
uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection,
|
||||
bool unmapAddressRange);
|
||||
area_id vm_map_physical_memory(team_id team, const char *name, void **address,
|
||||
uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr);
|
||||
area_id vm_map_file(team_id aid, const char *name, void **address,
|
||||
uint32 addressSpec, addr_t size, uint32 protection, uint32 mapping,
|
||||
const char *path, off_t offset);
|
||||
int fd, off_t offset);
|
||||
struct vm_cache *vm_area_get_locked_cache(struct vm_area *area);
|
||||
void vm_area_put_locked_cache(struct vm_cache *cache);
|
||||
area_id vm_create_null_area(team_id team, const char *name, void **address,
|
||||
@@ -144,8 +148,9 @@ off_t vm_available_memory(void);
|
||||
area_id _user_create_area(const char *name, void **address, uint32 addressSpec,
|
||||
size_t size, uint32 lock, uint32 protection);
|
||||
status_t _user_delete_area(area_id area);
|
||||
area_id _user_vm_map_file(const char *uname, void **uaddress, int addr_type,
|
||||
addr_t size, int lock, int mapping, const char *upath, off_t offset);
|
||||
area_id _user_map_file(const char *uname, void **uaddress, int addressSpec,
|
||||
addr_t size, int protection, int mapping, int fd, off_t offset);
|
||||
status_t _user_unmap_memory(void *address, addr_t size);
|
||||
area_id _user_area_for(void *address);
|
||||
area_id _user_find_area(const char *name);
|
||||
status_t _user_get_area_info(area_id area, area_info *info);
|
||||
|
||||
@@ -1406,7 +1406,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr
|
||||
B_EXACT_ADDRESS,
|
||||
fileUpperBound,
|
||||
B_READ_AREA | B_WRITE_AREA, REGION_PRIVATE_MAP,
|
||||
path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
|
||||
fd, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
|
||||
if (id < B_OK) {
|
||||
dprintf("error mapping file data: %s!\n", strerror(id));
|
||||
status = B_NOT_AN_EXECUTABLE;
|
||||
@@ -1453,7 +1453,7 @@ elf_load_user_image(const char *path, struct team *team, int flags, addr_t *entr
|
||||
B_EXACT_ADDRESS,
|
||||
ROUNDUP(programHeaders[i].p_memsz + (programHeaders[i].p_vaddr % B_PAGE_SIZE), B_PAGE_SIZE),
|
||||
B_READ_AREA | B_EXECUTE_AREA, REGION_PRIVATE_MAP,
|
||||
path, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
|
||||
fd, ROUNDOWN(programHeaders[i].p_offset, B_PAGE_SIZE));
|
||||
if (id < B_OK) {
|
||||
dprintf("error mapping file text: %s!\n", strerror(id));
|
||||
status = B_NOT_AN_EXECUTABLE;
|
||||
|
||||
+151
-48
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <fs/fd.h>
|
||||
#include <vm_address_space.h>
|
||||
#include <vm_priv.h>
|
||||
#include <vm_page.h>
|
||||
@@ -1185,6 +1186,43 @@ insert_area(vm_address_space *addressSpace, void **_address,
|
||||
}
|
||||
|
||||
|
||||
/*! Deletes all areas in the given address range.
|
||||
The address space must be write-locked.
|
||||
NOTE: At the moment deleting only complete areas is supported.
|
||||
*/
|
||||
static status_t
|
||||
unmap_address_range(vm_address_space *addressSpace, addr_t address, addr_t size)
|
||||
{
|
||||
// TODO: Support deleting partial areas!
|
||||
|
||||
addr_t lastAddress = address + (size - 1);
|
||||
|
||||
// check whether any areas are only partially covered
|
||||
vm_area* area = vm_area_lookup(addressSpace, address);
|
||||
if (area != NULL && area->base < address)
|
||||
return B_UNSUPPORTED;
|
||||
|
||||
area = vm_area_lookup(addressSpace, lastAddress);
|
||||
if (area != NULL && lastAddress - area->base < area->size - 1)
|
||||
return B_UNSUPPORTED;
|
||||
|
||||
// all areas (if any) are fully covered; let's delete them
|
||||
area = addressSpace->areas;
|
||||
while (area != NULL) {
|
||||
vm_area* nextArea = area->address_space_next;
|
||||
|
||||
if (area->id != RESERVED_AREA_ID) {
|
||||
if (area->base >= address && area->base < lastAddress)
|
||||
delete_area(addressSpace, area);
|
||||
}
|
||||
|
||||
area = nextArea;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! You need to hold the lock of the cache and the write lock of the address
|
||||
space when calling this function.
|
||||
Note, that in case of error your cache will be temporarily unlocked.
|
||||
@@ -1193,7 +1231,7 @@ static status_t
|
||||
map_backing_store(vm_address_space *addressSpace, vm_cache *cache,
|
||||
void **_virtualAddress, off_t offset, addr_t size, uint32 addressSpec,
|
||||
int wiring, int protection, int mapping, vm_area **_area,
|
||||
const char *areaName)
|
||||
const char *areaName, bool unmapAddressRange)
|
||||
{
|
||||
TRACE(("map_backing_store: aspace %p, cache %p, *vaddr %p, offset 0x%Lx, size %lu, addressSpec %ld, wiring %d, protection %d, _area %p, area_name '%s'\n",
|
||||
addressSpace, cache, *_virtualAddress, offset, size, addressSpec,
|
||||
@@ -1254,6 +1292,13 @@ map_backing_store(vm_address_space *addressSpace, vm_cache *cache,
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (addressSpec == B_EXACT_ADDRESS && unmapAddressRange) {
|
||||
status = unmap_address_range(addressSpace, (addr_t)*_virtualAddress,
|
||||
size);
|
||||
if (status != B_OK)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
status = insert_area(addressSpace, _virtualAddress, addressSpec, size, area);
|
||||
if (status < B_OK)
|
||||
goto err2;
|
||||
@@ -1379,7 +1424,8 @@ vm_reserve_address_range(team_id team, void **_address, uint32 addressSpec,
|
||||
|
||||
area_id
|
||||
vm_create_anonymous_area(team_id team, const char *name, void **address,
|
||||
uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection)
|
||||
uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection,
|
||||
bool unmapAddressRange)
|
||||
{
|
||||
vm_area *area;
|
||||
vm_cache *cache;
|
||||
@@ -1482,7 +1528,8 @@ vm_create_anonymous_area(team_id team, const char *name, void **address,
|
||||
mutex_lock(&cache->lock);
|
||||
|
||||
status = map_backing_store(addressSpace, cache, address, 0, size,
|
||||
addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name);
|
||||
addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name,
|
||||
unmapAddressRange);
|
||||
|
||||
mutex_unlock(&cache->lock);
|
||||
|
||||
@@ -1696,7 +1743,7 @@ vm_map_physical_memory(team_id team, const char *name, void **_address,
|
||||
|
||||
status_t status = map_backing_store(locker.AddressSpace(), cache, _address,
|
||||
0, size, addressSpec & ~B_MTR_MASK, B_FULL_LOCK, protection,
|
||||
REGION_NO_PRIVATE_MAP, &area, name);
|
||||
REGION_NO_PRIVATE_MAP, &area, name, false);
|
||||
|
||||
mutex_unlock(&cache->lock);
|
||||
|
||||
@@ -1777,7 +1824,8 @@ vm_create_null_area(team_id team, const char *name, void **address,
|
||||
mutex_lock(&cache->lock);
|
||||
|
||||
status = map_backing_store(locker.AddressSpace(), cache, address, 0, size,
|
||||
addressSpec, 0, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, &area, name);
|
||||
addressSpec, 0, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, &area, name,
|
||||
false);
|
||||
|
||||
mutex_unlock(&cache->lock);
|
||||
|
||||
@@ -1821,18 +1869,16 @@ err1:
|
||||
}
|
||||
|
||||
|
||||
/*! Will map the file at the path specified by \a name to an area in memory.
|
||||
The file will be mirrored beginning at the specified \a offset. The \a offset
|
||||
and \a size arguments have to be page aligned.
|
||||
/*! Will map the file specified by \a fd to an area in memory.
|
||||
The file will be mirrored beginning at the specified \a offset. The
|
||||
\a offset and \a size arguments have to be page aligned.
|
||||
*/
|
||||
static area_id
|
||||
_vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec,
|
||||
size_t size, uint32 protection, uint32 mapping, const char *path,
|
||||
off_t offset, bool kernel)
|
||||
size_t size, uint32 protection, uint32 mapping, int fd, off_t offset,
|
||||
bool kernel)
|
||||
{
|
||||
// ToDo: maybe attach to an FD, not a path (or both, like VFS calls)
|
||||
// ToDo: check file access permissions (would be already done if the above were true)
|
||||
// ToDo: for binary files, we want to make sure that they get the
|
||||
// TODO: for binary files, we want to make sure that they get the
|
||||
// copy of a file at a given time, ie. later changes should not
|
||||
// make it into the mapped copy -- this will need quite some changes
|
||||
// to be done in a nice way
|
||||
@@ -1842,38 +1888,56 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec
|
||||
offset = ROUNDOWN(offset, B_PAGE_SIZE);
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (mapping == REGION_NO_PRIVATE_MAP)
|
||||
protection |= B_SHARED_AREA;
|
||||
|
||||
if (fd < 0) {
|
||||
return vm_create_anonymous_area(team, name, _address, addressSpec, size,
|
||||
B_NO_LOCK, protection, addressSpec == B_EXACT_ADDRESS);
|
||||
}
|
||||
|
||||
// get the open flags of the FD
|
||||
file_descriptor *descriptor = get_fd(get_current_io_context(kernel), fd);
|
||||
if (descriptor == NULL)
|
||||
return EBADF;
|
||||
int32 openMode = descriptor->open_mode;
|
||||
put_fd(descriptor);
|
||||
|
||||
// The FD must open for reading at any rate. For shared mapping with write
|
||||
// access, additionally the FD must be open for writing.
|
||||
if ((openMode & O_ACCMODE) == O_WRONLY
|
||||
|| mapping == REGION_NO_PRIVATE_MAP
|
||||
&& (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0
|
||||
&& (openMode & O_ACCMODE) == O_RDONLY) {
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
// get the vnode for the object, this also grabs a ref to it
|
||||
struct vnode *vnode;
|
||||
status_t status = vfs_get_vnode_from_path(path, kernel, &vnode);
|
||||
struct vnode *vnode = NULL;
|
||||
status_t status = vfs_get_vnode_from_fd(fd, kernel, &vnode);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
CObjectDeleter<struct vnode> vnodePutter(vnode, vfs_put_vnode);
|
||||
|
||||
AddressSpaceWriteLocker locker(team);
|
||||
if (!locker.IsLocked()) {
|
||||
vfs_put_vnode(vnode);
|
||||
if (!locker.IsLocked())
|
||||
return B_BAD_TEAM_ID;
|
||||
}
|
||||
|
||||
// ToDo: this only works for file systems that use the file cache
|
||||
// TODO: this only works for file systems that use the file cache
|
||||
vm_cache *cache;
|
||||
status = vfs_get_vnode_cache(vnode, &cache, false);
|
||||
if (status < B_OK) {
|
||||
vfs_put_vnode(vnode);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
mutex_lock(&cache->lock);
|
||||
|
||||
vm_area *area;
|
||||
status = map_backing_store(locker.AddressSpace(), cache, _address,
|
||||
offset, size, addressSpec, 0, protection, mapping, &area, name);
|
||||
offset, size, addressSpec, 0, protection, mapping, &area, name,
|
||||
addressSpec == B_EXACT_ADDRESS);
|
||||
|
||||
mutex_unlock(&cache->lock);
|
||||
|
||||
vfs_put_vnode(vnode);
|
||||
// we don't need this vnode anymore - if the above call was
|
||||
// successful, the store already has a ref to it
|
||||
|
||||
if (status < B_OK || mapping == REGION_PRIVATE_MAP) {
|
||||
// map_backing_store() cannot know we no longer need the ref
|
||||
vm_cache_release_ref(cache);
|
||||
@@ -1888,14 +1952,13 @@ _vm_map_file(team_id team, const char *name, void **_address, uint32 addressSpec
|
||||
|
||||
area_id
|
||||
vm_map_file(team_id aid, const char *name, void **address, uint32 addressSpec,
|
||||
addr_t size, uint32 protection, uint32 mapping, const char *path,
|
||||
off_t offset)
|
||||
addr_t size, uint32 protection, uint32 mapping, int fd, off_t offset)
|
||||
{
|
||||
if (!arch_vm_supports_protection(protection))
|
||||
return B_NOT_SUPPORTED;
|
||||
|
||||
return _vm_map_file(aid, name, address, addressSpec, size, protection,
|
||||
mapping, path, offset, true);
|
||||
mapping, fd, offset, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1973,7 +2036,7 @@ vm_clone_area(team_id team, const char *name, void **address,
|
||||
else {
|
||||
status = map_backing_store(targetAddressSpace, cache, address,
|
||||
sourceArea->cache_offset, sourceArea->size, addressSpec,
|
||||
sourceArea->wiring, protection, mapping, &newArea, name);
|
||||
sourceArea->wiring, protection, mapping, &newArea, name, false);
|
||||
}
|
||||
if (status == B_OK && mapping != REGION_PRIVATE_MAP) {
|
||||
// If the mapping is REGION_PRIVATE_MAP, map_backing_store() needed
|
||||
@@ -2227,22 +2290,33 @@ vm_copy_area(team_id team, const char *name, void **_address,
|
||||
*_address = (void *)source->base;
|
||||
}
|
||||
|
||||
// First, create a cache on top of the source area
|
||||
bool sharedArea = (source->protection & B_SHARED_AREA) != 0;
|
||||
|
||||
// First, create a cache on top of the source area, respectively use the
|
||||
// existing one, if this is a shared area.
|
||||
|
||||
vm_area *target;
|
||||
status = map_backing_store(targetAddressSpace, cache, _address,
|
||||
source->cache_offset, source->size, addressSpec, source->wiring,
|
||||
protection, REGION_PRIVATE_MAP, &target, name);
|
||||
|
||||
protection, sharedArea ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP,
|
||||
&target, name, false);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (sharedArea) {
|
||||
// The new area uses the old area's cache, but map_backing_store()
|
||||
// hasn't acquired a ref. So we have to do that now.
|
||||
vm_cache_acquire_ref(cache);
|
||||
}
|
||||
|
||||
// If the source area is writable, we need to move it one layer up as well
|
||||
|
||||
if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) {
|
||||
// ToDo: do something more useful if this fails!
|
||||
if (vm_copy_on_write_area(cache) < B_OK)
|
||||
panic("vm_copy_on_write_area() failed!\n");
|
||||
if (!sharedArea) {
|
||||
if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) {
|
||||
// TODO: do something more useful if this fails!
|
||||
if (vm_copy_on_write_area(cache) < B_OK)
|
||||
panic("vm_copy_on_write_area() failed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// we return the ID of the newly created area
|
||||
@@ -5075,7 +5149,7 @@ create_area_etc(struct team *team, const char *name, void **address, uint32 addr
|
||||
fix_protection(&protection);
|
||||
|
||||
return vm_create_anonymous_area(team->id, (char *)name, address,
|
||||
addressSpec, size, lock, protection);
|
||||
addressSpec, size, lock, protection, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -5086,7 +5160,7 @@ create_area(const char *name, void **_address, uint32 addressSpec, size_t size,
|
||||
fix_protection(&protection);
|
||||
|
||||
return vm_create_anonymous_area(vm_kernel_address_space_id(), (char *)name, _address,
|
||||
addressSpec, size, lock, protection);
|
||||
addressSpec, size, lock, protection, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -5319,7 +5393,7 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
|
||||
fix_protection(&protection);
|
||||
|
||||
area_id area = vm_create_anonymous_area(vm_current_user_address_space_id(),
|
||||
(char *)name, &address, addressSpec, size, lock, protection);
|
||||
(char *)name, &address, addressSpec, size, lock, protection, false);
|
||||
|
||||
if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
|
||||
delete_area(area);
|
||||
@@ -5344,26 +5418,33 @@ _user_delete_area(area_id area)
|
||||
// ToDo: create a BeOS style call for this!
|
||||
|
||||
area_id
|
||||
_user_vm_map_file(const char *userName, void **userAddress, int addressSpec,
|
||||
addr_t size, int protection, int mapping, const char *userPath, off_t offset)
|
||||
_user_map_file(const char *userName, void **userAddress, int addressSpec,
|
||||
addr_t size, int protection, int mapping, int fd, off_t offset)
|
||||
{
|
||||
char name[B_OS_NAME_LENGTH];
|
||||
char path[B_PATH_NAME_LENGTH];
|
||||
void *address;
|
||||
area_id area;
|
||||
|
||||
if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userAddress)
|
||||
|| !IS_USER_ADDRESS(userPath)
|
||||
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK
|
||||
|| user_strlcpy(path, userPath, B_PATH_NAME_LENGTH) < B_OK
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
if (addressSpec == B_EXACT_ADDRESS) {
|
||||
if ((addr_t)address + size < (addr_t)address)
|
||||
return B_BAD_VALUE;
|
||||
if (!IS_USER_ADDRESS(address)
|
||||
|| !IS_USER_ADDRESS((addr_t)address + size)) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
// userland created areas can always be accessed by the kernel
|
||||
protection |= B_KERNEL_READ_AREA | (protection & B_WRITE_AREA ? B_KERNEL_WRITE_AREA : 0);
|
||||
protection |= B_KERNEL_READ_AREA
|
||||
| (protection & B_WRITE_AREA ? B_KERNEL_WRITE_AREA : 0);
|
||||
|
||||
area = _vm_map_file(vm_current_user_address_space_id(), name, &address,
|
||||
addressSpec, size, protection, mapping, path, offset, false);
|
||||
addressSpec, size, protection, mapping, fd, offset, false);
|
||||
if (area < B_OK)
|
||||
return area;
|
||||
|
||||
@@ -5373,3 +5454,25 @@ _user_vm_map_file(const char *userName, void **userAddress, int addressSpec,
|
||||
return area;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_user_unmap_memory(void *_address, addr_t size)
|
||||
{
|
||||
addr_t address = (addr_t)_address;
|
||||
|
||||
// check params
|
||||
if (size == 0 || (addr_t)address + size < (addr_t)address)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!IS_USER_ADDRESS(address) || !IS_USER_ADDRESS((addr_t)address + size))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
// write lock the address space
|
||||
AddressSpaceWriteLocker locker;
|
||||
status_t status = locker.SetTo(team_get_current_team_id());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// unmap
|
||||
return unmap_address_range(locker.AddressSpace(), address, size);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
SubDir HAIKU_TOP src system libroot posix sys ;
|
||||
|
||||
UsePrivateHeaders shared ;
|
||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
|
||||
MergeObject posix_sys.o :
|
||||
@@ -11,6 +12,7 @@ MergeObject posix_sys.o :
|
||||
itimer.c
|
||||
mkdir.c
|
||||
mkfifo.c
|
||||
mman.cpp
|
||||
rlimit.c
|
||||
select.c
|
||||
stat.c
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <syscall_utils.h>
|
||||
#include <syscalls.h>
|
||||
#include <vm.h>
|
||||
|
||||
|
||||
void*
|
||||
mmap(void* address, size_t length, int protection, int flags, int fd,
|
||||
off_t offset)
|
||||
{
|
||||
// offset and length must be page-aligned
|
||||
if (length == 0 || (offset | length) % B_PAGE_SIZE != 0) {
|
||||
errno = B_BAD_VALUE;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
// check anonymous mapping
|
||||
if ((flags & MAP_ANONYMOUS) != 0) {
|
||||
fd = -1;
|
||||
} else if (fd < 0) {
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
// either MAP_SHARED or MAP_PRIVATE must be specified
|
||||
if (((flags & MAP_SHARED) != 0) == ((flags & MAP_PRIVATE) != 0)) {
|
||||
errno = B_BAD_VALUE;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
// translate mapping, address specification, and protection
|
||||
int mapping = (flags & MAP_SHARED) != 0
|
||||
? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP;
|
||||
|
||||
uint32 addressSpec = B_ANY_ADDRESS;
|
||||
if ((flags & MAP_FIXED) != 0)
|
||||
addressSpec = B_EXACT_ADDRESS;
|
||||
|
||||
uint32 areaProtection = 0;
|
||||
if ((protection & PROT_READ) != 0)
|
||||
areaProtection |= B_READ_AREA;
|
||||
if ((protection & PROT_WRITE) != 0)
|
||||
areaProtection |= B_WRITE_AREA;
|
||||
if ((protection & PROT_EXEC) != 0)
|
||||
areaProtection |= B_EXECUTE_AREA;
|
||||
|
||||
// ask the kernel to map
|
||||
area_id area = _kern_map_file("mmap area", &address, addressSpec,
|
||||
length, areaProtection, mapping, fd, offset);
|
||||
if (area < 0) {
|
||||
errno = area;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
munmap(void* address, size_t length)
|
||||
{
|
||||
RETURN_AND_SET_ERRNO(_kern_unmap_memory(address, length));
|
||||
}
|
||||
@@ -794,9 +794,10 @@ map_image(int fd, char const *path, image_t *image, bool fixed)
|
||||
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
|
||||
image->regions[i].vmstart = loadAddress;
|
||||
} else {
|
||||
image->regions[i].id = sys_vm_map_file(regionName, (void **)&loadAddress,
|
||||
addressSpecifier, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
|
||||
REGION_PRIVATE_MAP, path, PAGE_BASE(image->regions[i].fdstart));
|
||||
image->regions[i].id = _kern_map_file(regionName,
|
||||
(void **)&loadAddress, addressSpecifier,
|
||||
image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
|
||||
REGION_PRIVATE_MAP, fd, PAGE_BASE(image->regions[i].fdstart));
|
||||
|
||||
if (image->regions[i].id < 0) {
|
||||
status = image->regions[i].id;
|
||||
|
||||
Reference in New Issue
Block a user