1 /*
2 * Copyright (c) 2024, Tenstorrent AI ULC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stddef.h>
9 #include <sys/types.h>
10
11 #include <kernel_arch_interface.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/kernel/mm.h>
14 #include <zephyr/sys/fdtable.h>
15 #include <zephyr/posix/sys/mman.h>
16 #include <zephyr/posix/unistd.h>
17
18 #define _page_size COND_CODE_1(CONFIG_MMU, (CONFIG_MMU_PAGE_SIZE), (PAGE_SIZE))
19
20 int zvfs_ioctl(int fd, int cmd, va_list args);
21
p2z(int prot,int pflags)22 static int p2z(int prot, int pflags)
23 {
24 bool rw = (prot & PROT_WRITE) != 0;
25 bool ex = (prot & PROT_EXEC) != 0;
26 bool fixed = (pflags & MAP_FIXED) != 0;
27 bool shared = (pflags & MAP_SHARED) != 0;
28 bool private = (pflags & MAP_PRIVATE) != 0;
29
30 if (!(shared ^ private)) {
31 return -1;
32 }
33
34 return (rw * K_MEM_PERM_RW) | (ex * K_MEM_PERM_EXEC) | (fixed * K_MEM_DIRECT_MAP);
35 }
36
zvfs_ioctl_wrap(int fd,int cmd,...)37 static inline int zvfs_ioctl_wrap(int fd, int cmd, ...)
38 {
39 int ret;
40 va_list args;
41
42 va_start(args, cmd);
43 ret = zvfs_ioctl(fd, cmd, args);
44 va_end(args);
45
46 return ret;
47 }
48
mmap(void * addr,size_t len,int prot,int flags,int fd,off_t off)49 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
50 {
51 void *virt;
52 uintptr_t phys;
53 int zflags = p2z(prot, flags);
54
55 if ((len == 0) || (zflags == -1)) {
56 errno = EINVAL;
57 return MAP_FAILED;
58 }
59
60 if ((flags & MAP_ANONYMOUS) != 0) {
61 /* force behaviour to be in-line with Linux, fd is ignored */
62 fd = -1;
63 }
64
65 if (fd > 0) {
66 /* non-anonymous mapping */
67 virt = NULL;
68 if (zvfs_ioctl_wrap(fd, ZFD_IOCTL_MMAP, addr, len, prot, flags, off, &virt) < 0) {
69 return MAP_FAILED;
70 }
71
72 return virt;
73 }
74
75 if (!IS_ENABLED(CONFIG_MMU)) {
76 errno = ENOTSUP;
77 return MAP_FAILED;
78 }
79
80 if ((flags & MAP_FIXED) == 0) {
81 /* anonymous mapping */
82 virt = k_mem_map(len, zflags);
83 } else {
84 /* a physical mapping. Care should be taken not to map the same page twice */
85 virt = NULL;
86 phys = POINTER_TO_UINT(addr);
87 k_mem_map_phys_bare((uint8_t **)&virt, phys, (size_t)ROUND_UP(len, _page_size),
88 zflags);
89 }
90
91 if (virt == NULL) {
92 errno = ENOMEM;
93 return MAP_FAILED;
94 }
95
96 return virt;
97 }
98
msync(void * addr,size_t length,int flags)99 int msync(void *addr, size_t length, int flags)
100 {
101 ARG_UNUSED(addr);
102 ARG_UNUSED(length);
103 ARG_UNUSED(flags);
104
105 return 0;
106 }
107
munmap(void * addr,size_t len)108 int munmap(void *addr, size_t len)
109 {
110 if (len == 0) {
111 errno = EINVAL;
112 return -1;
113 }
114
115 if (!IS_ENABLED(CONFIG_MMU)) {
116 /* cannot munmap without an MPU */
117 errno = ENOTSUP;
118 return -1;
119 }
120
121 uintptr_t phys = 0;
122
123 if (arch_page_phys_get(addr, &phys) == 0) {
124 k_mem_unmap(addr, ROUND_UP(len, _page_size));
125 }
126
127 return 0;
128 }
129