1#include <errno.h>
2#include <limits.h>
3#include <zircon/process.h>
4#include <zircon/syscalls.h>
5#include <zircon/syscalls/object.h>
6#include <stdint.h>
7#include <string.h>
8#include <sys/mman.h>
9#include <unistd.h>
10
11#include "zircon_impl.h"
12#include "threads_impl.h"
13#include "stdio_impl.h"
14
15static const char mmap_vmo_name[] = "mmap-anonymous";
16
17void* __mmap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) {
18    if (fd_off & (PAGE_SIZE - 1)) {
19        errno = EINVAL;
20        return MAP_FAILED;
21    }
22    if (len == 0) {
23        errno = EINVAL;
24        return MAP_FAILED;
25    }
26    if (len >= PTRDIFF_MAX) {
27        errno = ENOMEM;
28        return MAP_FAILED;
29    }
30    if (!(flags & (MAP_PRIVATE | MAP_SHARED)) ||
31        (flags & MAP_PRIVATE && flags & MAP_SHARED)) {
32        errno = EINVAL;
33        return MAP_FAILED;
34    }
35
36    // round up to page size
37    len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
38
39    // build zircon flags for this
40    zx_vm_option_t zx_options = 0;
41    zx_options |= (prot & PROT_READ) ? ZX_VM_PERM_READ : 0;
42    zx_options |= (prot & PROT_WRITE) ? ZX_VM_PERM_WRITE : 0;
43    zx_options |= (prot & PROT_EXEC) ? ZX_VM_PERM_EXECUTE : 0;
44
45    size_t offset = 0;
46    zx_status_t status = ZX_OK;
47    if (flags & MAP_FIXED) {
48        zx_options |= ZX_VM_SPECIFIC;
49
50        zx_info_vmar_t info;
51        status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
52                                     sizeof(info), NULL, NULL);
53        if (status < 0 || (uintptr_t)start < info.base) {
54            goto fail;
55        }
56        offset = (uintptr_t)start - info.base;
57    }
58
59    zx_handle_t vmo;
60    uintptr_t ptr = 0;
61    if (flags & MAP_ANON) {
62        if (_zx_vmo_create(len, 0, &vmo) < 0) {
63            errno = ENOMEM;
64            return MAP_FAILED;
65        }
66        _zx_object_set_property(vmo, ZX_PROP_NAME, mmap_vmo_name, strlen(mmap_vmo_name));
67    } else {
68        status = _mmap_file(offset, len, zx_options, flags, fd, fd_off, &ptr);
69        if (status < 0) {
70            goto fail;
71        }
72        return (void*) ptr;
73    }
74
75    status = _zx_vmar_map(_zx_vmar_root_self(), zx_options, offset, vmo, fd_off, len, &ptr);
76    _zx_handle_close(vmo);
77    // TODO: map this as shared if we ever implement forking
78    if (status < 0) {
79        goto fail;
80    }
81
82    return (void*)ptr;
83
84fail:
85    switch(status) {
86    case ZX_ERR_BAD_HANDLE:
87        errno = EBADF;
88        break;
89    case ZX_ERR_NOT_SUPPORTED:
90        errno = ENODEV;
91        break;
92    case ZX_ERR_ACCESS_DENIED:
93        errno = EACCES;
94        break;
95    case ZX_ERR_NO_MEMORY:
96        errno = ENOMEM;
97        break;
98    case ZX_ERR_INVALID_ARGS:
99    case ZX_ERR_BAD_STATE:
100    default:
101        errno = EINVAL;
102    }
103    return MAP_FAILED;
104}
105
106weak_alias(__mmap, mmap);
107