1 /*
2 * Copyright (c) 2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #ifndef ZEPHYR_DRIVERS_SYSTEM_MM_DRV_COMMON_H_
8 #define ZEPHYR_DRIVERS_SYSTEM_MM_DRV_COMMON_H_
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/toolchain.h>
12
13 #include <zephyr/drivers/mm/system_mm.h>
14
15 extern struct k_spinlock sys_mm_drv_common_lock;
16
17 /**
18 * @brief Get the flags of mapped virtual address.
19 *
20 * The function queries the translation tables to find the flags of
21 * a mapped virtual address. This is used internally for remapping.
22 *
23 * Behavior when providing unaligned address is undefined, this
24 * is assumed to be page aligned.
25 *
26 * @param virt Page-aligned virtual address
27 * @param[out] flags flags of mapped virtual address
28 *
29 * @retval 0 if mapping is found and valid
30 * @retval -EINVAL if invalid arguments are provided
31 * @retval -EFAULT if virtual address is not mapped
32 */
33 int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags);
34
35 /**
36 * @brief Test if address is page-aligned
37 *
38 * @param addr address to be tested
39 *
40 * @retval true if page-aligned
41 * @retval false if not page-aligned
42 */
sys_mm_drv_is_addr_aligned(uintptr_t addr)43 static inline bool sys_mm_drv_is_addr_aligned(uintptr_t addr)
44 {
45 return ((addr & (CONFIG_MM_DRV_PAGE_SIZE - 1)) == 0U);
46 }
47
48 /**
49 * @brief Test if address is page-aligned
50 *
51 * @param addr address to be tested
52 *
53 * @retval true if page-aligned
54 * @retval false if not page-aligned
55 */
sys_mm_drv_is_virt_addr_aligned(void * virt)56 static inline bool sys_mm_drv_is_virt_addr_aligned(void *virt)
57 {
58 return sys_mm_drv_is_addr_aligned(POINTER_TO_UINT(virt));
59 }
60
61 /**
62 * @brief Test if size is page-aligned
63 *
64 * @param addr size to be tested
65 *
66 * @retval true if page-aligned
67 * @retval false if not page-aligned
68 */
sys_mm_drv_is_size_aligned(size_t size)69 static inline bool sys_mm_drv_is_size_aligned(size_t size)
70 {
71 if ((size & (CONFIG_MM_DRV_PAGE_SIZE - 1)) == 0U) {
72 return true;
73 } else {
74 return false;
75 }
76 }
77
78 /**
79 * @brief Test if all physical addresses in array are page-aligned
80 *
81 * @param addr Array of physical addresses
82 * @param cnt Number of elements in the array
83 *
84 * @retval true if all are page-aligned
85 * @retval false if at least one is not page-aligned
86 */
87 bool sys_mm_drv_is_addr_array_aligned(uintptr_t *addr, size_t cnt);
88
89 /**
90 * @brief Test if the virtual memory region is mapped
91 *
92 * @param virt Page-aligned base virtual address
93 * @param size Size of the virtual memory region
94 *
95 * @retval true if all pages in the region are mapped
96 * @retval false if at least one page is not mapped
97 */
98 bool sys_mm_drv_is_virt_region_mapped(void *virt, size_t size);
99
100 /**
101 * @brief Test if the virtual memory region is unmapped
102 *
103 * @param virt Page-aligned base virtual address
104 * @param size Size of the virtual memory region
105 *
106 * @retval true if all pages in the region are unmapped
107 * @retval false if at least one page is mapped
108 */
109 bool sys_mm_drv_is_virt_region_unmapped(void *virt, size_t size);
110
111 /**
112 * @brief Simple implementation of sys_mm_drv_map_region()
113 *
114 * This provides a simple implementation for sys_mm_drv_map_region()
115 * which is marked as a weak alias to sys_mm_drv_map_region().
116 *
117 * Drivers do not have to implement their own sys_mm_drv_map_region()
118 * if this works for them. Or they can override sys_mm_drv_map_region()
119 * and call sys_mm_drv_simple_map_region() with some pre-processing done.
120 * Or the drivers can implement their own sys_mm_drv_map_region(), then
121 * this function will not be used.
122 *
123 * @see sys_mm_drv_map_region
124 *
125 * @param virt Page-aligned destination virtual address to map
126 * @param phys Page-aligned source physical address to map
127 * @param size Page-aligned size of the mapped memory region in bytes
128 * @param flags Caching, access and control flags, see SYS_MM_MEM_* macros
129 *
130 * @retval 0 if successful
131 * @retval -EINVAL if invalid arguments are provided
132 * @retval -EFAULT if any virtual addresses have already been mapped
133 */
134 int sys_mm_drv_simple_map_region(void *virt, uintptr_t phys,
135 size_t size, uint32_t flags);
136
137 /**
138 * @brief Simple implementation of sys_mm_drv_map_array()
139 *
140 * This provides a simple implementation for sys_mm_drv_map_array()
141 * which is marked as a weak alias to sys_mm_drv_map_array().
142 *
143 * Drivers do not have to implement their own sys_mm_drv_map_array()
144 * if this works for them. Or they can override sys_mm_drv_map_array()
145 * and call sys_mm_drv_simple_map_array() with some pre-processing done.
146 * Or the drivers can implement their own sys_mm_drv_map_array(), then
147 * this function will not be used.
148 *
149 * @see sys_mm_drv_map_array
150 *
151 * @param virt Page-aligned destination virtual address to map
152 * @param phys Array of pge-aligned source physical address to map
153 * @param cnt Number of elements in the physical page array
154 * @param flags Caching, access and control flags, see SYS_MM_MEM_* macros
155 *
156 * @retval 0 if successful
157 * @retval -EINVAL if invalid arguments are provided
158 * @retval -EFAULT if any virtual addresses have already been mapped
159 */
160 int sys_mm_drv_simple_map_array(void *virt, uintptr_t *phys,
161 size_t cnt, uint32_t flags);
162
163 /**
164 * @brief Simple implementation of sys_mm_drv_unmap_region()
165 *
166 * This provides a simple implementation for sys_mm_drv_unmap_region()
167 * which is marked as a weak alias to sys_mm_drv_unmap_region().
168 *
169 * Drivers do not have to implement their own sys_mm_drv_unmap_region()
170 * if this works for them. Or they can override sys_mm_drv_unmap_region()
171 * and call sys_mm_drv_simple_unmap_region() with some pre-processing done.
172 * Or the drivers can implement their own sys_mm_drv_unmap_region(), then
173 * this function will not be used.
174 *
175 * @see sys_mm_drv_unmap_region
176 *
177 * @param virt Page-aligned base virtual address to un-map
178 * @param size Page-aligned region size
179 *
180 * @retval 0 if successful
181 * @retval -EINVAL if invalid arguments are provided
182 * @retval -EFAULT if virtual addresses have already been mapped
183 */
184 int sys_mm_drv_simple_unmap_region(void *virt, size_t size);
185
186 /**
187 * @brief Simple implementation of sys_mm_drv_remap_region()
188 *
189 * This provides a simple implementation for sys_mm_drv_remap_region()
190 * which is marked as a weak alias to sys_mm_drv_remap_region().
191 *
192 * Drivers do not have to implement their own sys_mm_drv_remap_region()
193 * if this works for them. Or they can override sys_mm_drv_remap_region()
194 * and call sys_mm_drv_simple_remap_region() with some pre-processing done.
195 * Or the drivers can implement their own sys_mm_drv_remap_region(), then
196 * this function will not be used.
197 *
198 * @see sys_mm_drv_remap_region
199 *
200 * @param virt_old Page-aligned base virtual address of existing memory
201 * @param size Page-aligned size of the mapped memory region in bytes
202 * @param virt_new Page-aligned base virtual address to which to remap
203 * the memory
204 *
205 * @retval 0 if successful
206 * @retval -EINVAL if invalid arguments are provided
207 * @retval -EFAULT if old virtual addresses are not all mapped or
208 * new virtual addresses are not all unmapped
209 */
210 int sys_mm_drv_simple_remap_region(void *virt_old, size_t size,
211 void *virt_new);
212
213 /**
214 * @brief Simple implementation of sys_mm_drv_move_region()
215 *
216 * This provides a simple implementation for sys_mm_drv_move_region()
217 * which is marked as a weak alias to sys_mm_drv_move_region().
218 *
219 * Drivers do not have to implement their own sys_mm_drv_move_region()
220 * if this works for them. Or they can override sys_mm_drv_move_region()
221 * and call sys_mm_drv_simple_move_region() with some pre-processing done.
222 * Or the drivers can implement their own sys_mm_drv_move_region(), then
223 * this function will not be used.
224 *
225 * @see sys_mm_drv_move_region
226 *
227 * @param virt_old Page-aligned base virtual address of existing memory
228 * @param size Page-aligned size of the mapped memory region in bytes
229 * @param virt_new Page-aligned base virtual address to which to map
230 * new physical pages
231 * @param phys_new Page-aligned base physical address to contain
232 * the moved memory
233 *
234 * @retval 0 if successful
235 * @retval -EINVAL if invalid arguments are provided
236 * @retval -EFAULT if old virtual addresses are not all mapped or
237 * new virtual addresses are not all unmapped
238 */
239 int sys_mm_drv_simple_move_region(void *virt_old, size_t size,
240 void *virt_new, uintptr_t phys_new);
241
242 /**
243 * @brief Simple implementation of sys_mm_drv_move_array()
244 *
245 * This provides a simple implementation for sys_mm_drv_move_array()
246 * which is marked as a weak alias to sys_mm_drv_move_array().
247 *
248 * Drivers do not have to implement their own sys_mm_drv_move_array()
249 * if this works for them. Or they can override sys_mm_drv_move_array()
250 * and call sys_mm_drv_simple_move_array() with some pre-processing done.
251 * Or the drivers can implement their own sys_mm_drv_move_array(), then
252 * this function will not be used.
253 *
254 * @see sys_mm_drv_move_array
255 *
256 * @param virt_old Page-aligned base virtual address of existing memory
257 * @param size Page-aligned size of the mapped memory region in bytes
258 * @param virt_new Page-aligned base virtual address to which to map
259 * new physical pages
260 * @param phys_new Array of page-aligned physical address to contain
261 * the moved memory
262 * @param phys_cnt Number of elements in the physical page array
263 *
264 * @retval 0 if successful
265 * @retval -EINVAL if invalid arguments are provided
266 * @retval -EFAULT if old virtual addresses are not all mapped or
267 * new virtual addresses are not all unmapped
268 */
269 int sys_mm_drv_simple_move_array(void *virt_old, size_t size,
270 void *virt_new,
271 uintptr_t *phys_new, size_t phys_cnt);
272
273 /**
274 * @brief Update memory region flags
275 *
276 * This changes the attributes of physical memory which is already
277 * mapped to a virtual address. This is useful when use case of
278 * specific memory region changes.
279 * E.g. when the library/module code is copied to the memory then
280 * it needs to be read-write and after it has already
281 * been copied and library/module code is ready to be executed then
282 * attributes need to be changed to read-only/executable.
283 * Calling this API must not cause losing memory contents.
284 *
285 * @param virt Page-aligned virtual address to be updated
286 * @param size Page-aligned size of the mapped memory region in bytes
287 * @param flags Caching, access and control flags, see SYS_MM_MEM_* macros
288 *
289 * @retval 0 if successful
290 * @retval -EINVAL if invalid arguments are provided
291 * @retval -EFAULT if virtual addresses is not mapped
292 */
293
294 int sys_mm_drv_simple_update_region_flags(void *virt, size_t size, uint32_t flags);
295
296 #endif /* ZEPHYR_DRIVERS_SYSTEM_MM_DRV_COMMON_H_ */
297