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