blob: 5a13520d52963494dc8d4d2c0ead0fa19ce727da [file] [log] [blame]
#include <errno.h>
#include <limits.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include "zircon_impl.h"
#include "pthread_impl.h"
#include "stdio_impl.h"
static const char mmap_vmo_name[] = "mmap-anonymous";
void* __mmap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
if (fd_off & (PAGE_SIZE - 1)) {
errno = EINVAL;
return MAP_FAILED;
}
if (len == 0) {
errno = EINVAL;
return MAP_FAILED;
}
if (len >= PTRDIFF_MAX) {
errno = ENOMEM;
return MAP_FAILED;
}
if (!(flags & (MAP_PRIVATE | MAP_SHARED)) ||
(flags & MAP_PRIVATE && flags & MAP_SHARED)) {
errno = EINVAL;
return MAP_FAILED;
}
// round up to page size
len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
// build zircon flags for this
uint32_t zx_flags = 0;
zx_flags |= (prot & PROT_READ) ? ZX_VM_FLAG_PERM_READ : 0;
zx_flags |= (prot & PROT_WRITE) ? ZX_VM_FLAG_PERM_WRITE : 0;
zx_flags |= (prot & PROT_EXEC) ? ZX_VM_FLAG_PERM_EXECUTE : 0;
size_t offset = 0;
zx_status_t status = ZX_OK;
if (flags & MAP_FIXED) {
zx_flags |= ZX_VM_FLAG_SPECIFIC;
zx_info_vmar_t info;
status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
sizeof(info), NULL, NULL);
if (status < 0 || (uintptr_t)start < info.base) {
goto fail;
}
offset = (uintptr_t)start - info.base;
}
zx_handle_t vmo;
uintptr_t ptr = 0;
if (flags & MAP_ANON) {
if (_zx_vmo_create(len, 0, &vmo) < 0) {
errno = ENOMEM;
return MAP_FAILED;
}
_zx_object_set_property(vmo, ZX_PROP_NAME, mmap_vmo_name, strlen(mmap_vmo_name));
} else {
status = _mmap_file(offset, len, zx_flags, flags, fd, fd_off, &ptr);
if (status < 0) {
goto fail;
}
return (void*) ptr;
}
status = _zx_vmar_map(_zx_vmar_root_self(), offset, vmo, fd_off, len, zx_flags, &ptr);
_zx_handle_close(vmo);
// TODO: map this as shared if we ever implement forking
if (status < 0) {
goto fail;
}
return (void*)ptr;
fail:
switch(status) {
case ZX_ERR_BAD_HANDLE:
errno = EBADF;
break;
case ZX_ERR_NOT_SUPPORTED:
errno = ENODEV;
break;
case ZX_ERR_ACCESS_DENIED:
errno = EACCES;
break;
case ZX_ERR_NO_MEMORY:
errno = ENOMEM;
break;
case ZX_ERR_INVALID_ARGS:
case ZX_ERR_BAD_STATE:
default:
errno = EINVAL;
}
return MAP_FAILED;
}
weak_alias(__mmap, mmap);