1 /*
2 * Copyright (c) 2006-2020, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-10-28 Jesven first version
9 * 2021-02-12 lizhirui add 64-bit support for lwp_brk
10 * 2023-09-19 Shell add lwp_user_memory_remap_to_kernel
11 */
12 #ifndef __LWP_USER_MM_H__
13 #define __LWP_USER_MM_H__
14
15 #include <rthw.h>
16 #include <rtthread.h>
17
18 #ifdef ARCH_MM_MMU
19 #include <lwp.h>
20 #include <mmu.h>
21 #include <mm_aspace.h>
22 #include <mm_fault.h>
23 #include <mm_page.h>
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 #define LWP_MAP_FLAG_NONE 0x0000
30 #define LWP_MAP_FLAG_NOCACHE 0x0001
31 #define LWP_MAP_FLAG_MAP_FIXED 0x00010000ul
32 #define LWP_MAP_FLAG_PREFETCH 0x00020000ul
33
34 /**
35 * @brief Map files or devices into memory
36 * It will create a new mapping in the virtual address space of the target lwp
37 *
38 * @param lwp target process
39 * @param addr address from user space
40 * @param length length in bytes of mapping
41 * @param prot protect attribution of mapping
42 * @param flags flags of control
43 * @param fd file descriptor
44 * @param pgoffset offset to fd in 4096 bytes unit
45 * @return void* the address is successful, otherwise return MAP_FAILED
46 */
47 void* lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
48
49 /**
50 * @brief Unmap memory region in user space
51 *
52 * @param lwp target process
53 * @param addr address to unmap
54 * @param length length in bytes of unmapping
55 * @return int errno
56 */
57 int lwp_munmap(struct rt_lwp *lwp, void *addr, size_t length);
58
59 void *lwp_mremap(struct rt_lwp *lwp, void *old_address, size_t old_size,
60 size_t new_size, int flags, void *new_address);
61
62 /**
63 * @brief Test if address from user is accessible address by user
64 *
65 * @param lwp target process
66 * @param addr address from user space
67 * @param size the bytes to access
68 * @return int RT_FALSE/RT_TRUE
69 */
70 int lwp_user_accessible_ext(struct rt_lwp *lwp, void *addr, size_t size);
71
72 /**
73 * @brief Test if address from user is accessible address by user
74 * Same as lwp_user_accessible_ext except that lwp is current lwp
75 *
76 * @param addr address from user space
77 * @param size the bytes to access
78 * @return int RT_FALSE/RT_TRUE
79 */
80 int lwp_user_accessable(void *addr, size_t size);
81
82 /**
83 * @brief Copy n bytes data from src to dst.
84 * Same as std libc memcpy, except that both src and dst may come from
85 * user space. lwp_memcpy will test and select the implementation based
86 * on the memory attribution on run-time
87 *
88 * @param dst where the data writes to
89 * @param src where the data comes from
90 * @param size the bytes to copy
91 * @return void* the destination address
92 */
93 void *lwp_memcpy(void * __restrict dst, const void * __restrict src, size_t size);
94
95 /**
96 * @brief memcpy from address in user address space to kernel space buffer
97 *
98 * @param lwp target process
99 * @param dst kernel space address where the data writes to
100 * @param src user space address where the data comes from
101 * @param size the bytes to copy
102 * @return size_t the bytes copied
103 */
104 size_t lwp_data_get(struct rt_lwp *lwp, void *dst, void *src, size_t size);
105
106 /**
107 * @brief lwp_data_get except that lwp is current lwp
108 *
109 * @param dst kernel space address where the data writes to
110 * @param src user space address where the data comes from
111 * @param size the bytes to copy
112 * @return size_t the bytes copied
113 */
114 size_t lwp_get_from_user(void *dst, void *src, size_t size);
115
116 /**
117 * @brief memcpy from kernel space buffer to address in user address space
118 *
119 * @param lwp target process
120 * @param dst user space address where the data writes to
121 * @param src kernel space address where the data comes from
122 * @param size the bytes to copy
123 * @return size_t the bytes copied
124 */
125 size_t lwp_data_put(struct rt_lwp *lwp, void *dst, void *src, size_t size);
126
127 /**
128 * @brief lwp_data_put except that lwp is current lwp
129 *
130 * @param dst user space address where the data writes to
131 * @param src kernel space address where the data comes from
132 * @param size the bytes to copy
133 * @return size_t the bytes copied
134 */
135 size_t lwp_put_to_user(void *dst, void *src, size_t size);
136
137 /**
138 * @brief memset to address in user address space
139 *
140 * @param lwp target process
141 * @param dst user space address where the data writes to
142 * @param c the value to write
143 * @param size the bytes to copy
144 * @return size_t the bytes written
145 */
146 size_t lwp_data_set(struct rt_lwp *lwp, void *dst, int c, size_t size);
147
148 int lwp_user_space_init(struct rt_lwp *lwp, rt_bool_t is_fork);
149 void lwp_unmap_user_space(struct rt_lwp *lwp);
150
151 int lwp_unmap_user(struct rt_lwp *lwp, void *va);
152 void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, rt_bool_t text);
153
154 rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
155
156 /* check LWP_MAP_FLAG_* */
157 rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags);
158
159 void *lwp_map_user_phy(struct rt_lwp *lwp, void *map_va, void *map_pa, size_t map_size, rt_bool_t cached);
160 int lwp_unmap_user_phy(struct rt_lwp *lwp, void *va);
161
162 rt_base_t lwp_brk(void *addr);
163
164 size_t lwp_user_strlen(const char *s);
165 size_t lwp_user_strlen_ext(struct rt_lwp *lwp, const char *s);
166 size_t lwp_strlen(struct rt_lwp *lwp, const char *s);
167
168 int lwp_fork_aspace(struct rt_lwp *dest_lwp, struct rt_lwp *src_lwp);
169
170 void lwp_data_cache_flush(struct rt_lwp *lwp, void *vaddr, size_t size);
171
_lwp_v2p(struct rt_lwp * lwp,void * vaddr)172 static inline void *_lwp_v2p(struct rt_lwp *lwp, void *vaddr)
173 {
174 return rt_hw_mmu_v2p(lwp->aspace, vaddr);
175 }
176
lwp_v2p(struct rt_lwp * lwp,void * vaddr)177 static inline void *lwp_v2p(struct rt_lwp *lwp, void *vaddr)
178 {
179 RD_LOCK(lwp->aspace);
180 void *paddr = _lwp_v2p(lwp, vaddr);
181 RD_UNLOCK(lwp->aspace);
182 return paddr;
183 }
184
185 /**
186 * @brief Remapping user space memory region to kernel
187 *
188 * @warning the remapped region in kernel should be unmapped after usage
189 *
190 * @param lwp target process
191 * @param uaddr user space address where the data writes to
192 * @param length the bytes to redirect
193 * @return void * the redirection address in kernel space
194 */
195 void *lwp_user_memory_remap_to_kernel(rt_lwp_t lwp, void *uaddr, size_t length);
196
lwp_user_mm_flag_to_kernel(int flags)197 rt_inline rt_size_t lwp_user_mm_flag_to_kernel(int flags)
198 {
199 rt_size_t k_flags = 0;
200 if (flags & MAP_FIXED)
201 k_flags |= MMF_MAP_FIXED;
202 if (flags & (MAP_PRIVATE | MAP_ANON | MAP_ANONYMOUS))
203 k_flags |= MMF_MAP_PRIVATE;
204 if (flags & MAP_SHARED)
205 k_flags |= MMF_MAP_SHARED;
206 return k_flags;
207 }
208
209 #ifndef MMU_MAP_U_ROCB
210 #define MMU_MAP_U_ROCB MMU_MAP_U_RWCB
211 #endif /* MMU_MAP_U_ROCB */
212
lwp_user_mm_attr_to_kernel(int prot)213 rt_inline rt_size_t lwp_user_mm_attr_to_kernel(int prot)
214 {
215 RT_UNUSED(prot);
216
217 rt_size_t k_attr = 0;
218
219 #ifdef LWP_USING_MPROTECT
220 if ((prot & PROT_EXEC) || (prot & PROT_WRITE) ||
221 ((prot & PROT_READ) && (prot & PROT_WRITE)))
222 k_attr = MMU_MAP_U_RWCB;
223 else if (prot == PROT_NONE)
224 k_attr = MMU_MAP_K_RWCB;
225 else
226 k_attr = MMU_MAP_U_ROCB;
227 #else /* !LWP_USING_MPROTECT */
228 k_attr = MMU_MAP_U_RWCB;
229 #endif /* LWP_USING_MPROTECT */
230
231 return k_attr;
232 }
233
234 #ifdef __cplusplus
235 }
236 #endif
237
238 #endif
239
240 #endif /*__LWP_USER_MM_H__*/
241