]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/mman/mman.c
Implement the critical part of wasi_thread_start in asm (#376)
[wasi-libc.git] / libc-bottom-half / mman / mman.c
1 // Userspace emulation of mmap and munmap. Restrictions apply.
2 //
3 // This is meant to be complete enough to be compatible with code that uses
4 // mmap for simple file I/O. It just allocates memory with malloc and reads
5 // and writes data with pread and pwrite.
6
7 #define _WASI_EMULATED_MMAN
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/types.h>
14
15 struct map {
16 int prot;
17 int flags;
18 off_t offset;
19 size_t length;
20 };
21
22 void *mmap(void *addr, size_t length, int prot, int flags,
23 int fd, off_t offset) {
24 // Check for unsupported flags.
25 if ((flags & (MAP_PRIVATE | MAP_SHARED)) == 0 ||
26 (flags & MAP_FIXED) != 0 ||
27 #ifdef MAP_SHARED_VALIDATE
28 (flags & MAP_SHARED_VALIDATE) == MAP_SHARED_VALIDATE ||
29 #endif
30 #ifdef MAP_NORESERVE
31 (flags & MAP_NORESERVE) != 0 ||
32 #endif
33 #ifdef MAP_GROWSDOWN
34 (flags & MAP_GROWSDOWN) != 0 ||
35 #endif
36 #ifdef MAP_HUGETLB
37 (flags & MAP_HUGETLB) != 0 ||
38 #endif
39 #ifdef MAP_FIXED_NOREPLACE
40 (flags & MAP_FIXED_NOREPLACE) != 0 ||
41 #endif
42 0)
43 {
44 errno = EINVAL;
45 return MAP_FAILED;
46 }
47
48 // Check for unsupported protection requests.
49 if (prot == PROT_NONE ||
50 #ifdef PROT_EXEC
51 (prot & PROT_EXEC) != 0 ||
52 #endif
53 0)
54 {
55 errno = EINVAL;
56 return MAP_FAILED;
57 }
58
59 // To be consistent with POSIX.
60 if (length == 0) {
61 errno = EINVAL;
62 return MAP_FAILED;
63 }
64
65 // Check for integer overflow.
66 size_t buf_len = 0;
67 if (__builtin_add_overflow(length, sizeof(struct map), &buf_len)) {
68 errno = ENOMEM;
69 return MAP_FAILED;
70 }
71
72 // Allocate the memory.
73 struct map *map = malloc(buf_len);
74 if (!map) {
75 errno = ENOMEM;
76 return MAP_FAILED;
77 }
78
79 // Initialize the header.
80 map->prot = prot;
81 map->flags = flags;
82 map->offset = offset;
83 map->length = length;
84
85 // Initialize the main memory buffer, either with the contents of a file,
86 // or with zeros.
87 addr = map + 1;
88 if ((flags & MAP_ANON) == 0) {
89 char *body = (char *)addr;
90 while (length > 0) {
91 const ssize_t nread = pread(fd, body, length, offset);
92 if (nread < 0) {
93 if (errno == EINTR)
94 continue;
95 return MAP_FAILED;
96 }
97 if (nread == 0)
98 break;
99 length -= (size_t)nread;
100 offset += (size_t)nread;
101 body += (size_t)nread;
102 }
103 } else {
104 memset(addr, 0, length);
105 }
106
107 return addr;
108 }
109
110 int munmap(void *addr, size_t length) {
111 struct map *map = (struct map *)addr - 1;
112
113 // We don't support partial munmapping.
114 if (map->length != length) {
115 errno = EINVAL;
116 return -1;
117 }
118
119 // Release the memory.
120 free(map);
121
122 // Success!
123 return 0;
124 }