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