1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-09-25 tangzz98 the first version
9 */
10
11 #include "mprotect.h"
12
13 #define DBG_ENABLE
14 #define DBG_SECTION_NAME "MEMORY PROTECTION"
15 #define DBG_LEVEL DBG_ERROR
16 #include <rtdbg.h>
17
18 rt_mem_exclusive_region_t exclusive_regions[NUM_EXCLUSIVE_REGIONS] = {};
19
rt_mprotect_find_free_region(rt_thread_t thread)20 rt_mem_region_t *rt_mprotect_find_free_region(rt_thread_t thread)
21 {
22 rt_uint8_t i;
23 rt_mem_region_t *free_region = RT_NULL;
24 if (thread->mem_regions != RT_NULL)
25 {
26 for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
27 {
28 if (((rt_mem_region_t *)thread->mem_regions)[i].size == 0)
29 {
30 free_region = &(((rt_mem_region_t *)thread->mem_regions)[i]);
31 break;
32 }
33 }
34 }
35
36 return free_region;
37 }
38
rt_mprotect_find_region(rt_thread_t thread,rt_mem_region_t * region)39 rt_mem_region_t *rt_mprotect_find_region(rt_thread_t thread, rt_mem_region_t *region)
40 {
41 rt_uint8_t i;
42 rt_mem_region_t *found_region = RT_NULL;
43 if (thread->mem_regions != RT_NULL)
44 {
45 for (i = 0U; i < NUM_DYNAMIC_REGIONS; i++)
46 {
47 if ((((rt_mem_region_t *)thread->mem_regions)[i].start == region->start) && (((rt_mem_region_t *)thread->mem_regions)[i].size == region->size))
48 {
49 found_region = &(((rt_mem_region_t *)thread->mem_regions)[i]);
50 break;
51 }
52 }
53 }
54
55 return found_region;
56 }
57
58 /**
59 * @brief This function will initialize memory protection.
60 *
61 * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
62 * When the return value is any other values, it means the initialization failed.
63 */
rt_mprotect_init(void)64 int rt_mprotect_init(void)
65 {
66 return (int)rt_hw_mpu_init();
67 }
68
69 /**
70 * @brief The function will add a memory region configuraiton for a thread.
71 *
72 * @param thread is the thread that the memory region configuration will apply to.
73 *
74 * @param region is the configuration for the memory region to add.
75 *
76 * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
77 * If the return value is any other values, it represents the operation failed.
78 */
rt_mprotect_add_region(rt_thread_t thread,rt_mem_region_t * region)79 rt_err_t rt_mprotect_add_region(rt_thread_t thread, rt_mem_region_t *region)
80 {
81 if (thread == RT_NULL)
82 {
83 thread = rt_thread_self();
84 }
85 if (thread->mem_regions == RT_NULL)
86 {
87 thread->mem_regions = RT_KERNEL_MALLOC(NUM_DYNAMIC_REGIONS * sizeof(rt_mem_region_t));
88 if (thread->mem_regions == RT_NULL)
89 {
90 return RT_ERROR;
91 }
92 rt_memset(thread->mem_regions, 0U, sizeof(rt_mem_region_t ) * NUM_DYNAMIC_REGIONS);
93 }
94 return rt_hw_mpu_add_region(thread, region);
95 }
96
97 /**
98 * @brief The function will delete an existing memory region configuraiton for a thread.
99 *
100 * @param thread is the thread that the memory region configuration will apply to.
101 *
102 * @param region is the configuration for the memory region to delete.
103 *
104 * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
105 * If the return value is any other values, it represents the operation failed.
106 */
rt_mprotect_delete_region(rt_thread_t thread,rt_mem_region_t * region)107 rt_err_t rt_mprotect_delete_region(rt_thread_t thread, rt_mem_region_t *region)
108 {
109 if (thread == RT_NULL)
110 {
111 thread = rt_thread_self();
112 }
113 return rt_hw_mpu_delete_region(thread, region);
114 }
115
116 /**
117 * @brief The function will update an existing memory region configuraiton for a thread.
118 *
119 * @param thread is the thread that the memory region configuration will apply to.
120 *
121 * @param region is the new configuration for the memory region.
122 *
123 * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
124 * If the return value is any other values, it represents the operation failed.
125 */
rt_mprotect_update_region(rt_thread_t thread,rt_mem_region_t * region)126 rt_err_t rt_mprotect_update_region(rt_thread_t thread, rt_mem_region_t *region)
127 {
128 if (thread == RT_NULL)
129 {
130 thread = rt_thread_self();
131 }
132 return rt_hw_mpu_update_region(thread, region);
133 }
134
135 /**
136 * @brief The function will add a memory region that is only accessible by the calling thread.
137 *
138 * @param start is the start address of the memory region.
139 *
140 * @param size is the size of the memory region.
141 *
142 * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
143 * If the return value is any other values, it represents the operation failed.
144 */
rt_mprotect_add_exclusive_region(void * start,rt_size_t size)145 rt_err_t rt_mprotect_add_exclusive_region(void *start, rt_size_t size)
146 {
147 rt_uint8_t i;
148 rt_mem_exclusive_region_t region;
149 region.owner = rt_thread_self();
150 region.region.start = start;
151 region.region.size = size;
152 region.region.attr = RT_MEM_REGION_P_NA_U_NA;
153 if (rt_hw_mpu_add_region(RT_NULL, (rt_mem_region_t *)(&(region.region))) != RT_EOK)
154 {
155 return RT_ERROR;
156 }
157 rt_enter_critical();
158 for (i = 0; i < NUM_EXCLUSIVE_REGIONS; i++)
159 {
160 if (exclusive_regions[i].owner == RT_NULL)
161 {
162 rt_memcpy(&(exclusive_regions[i]), ®ion, sizeof(rt_mem_exclusive_region_t));
163 rt_exit_critical();
164 return RT_EOK;
165 }
166 }
167 rt_exit_critical();
168 LOG_E("Insufficient regions");
169 return RT_ERROR;
170 }
171
172 /**
173 * @brief The function will delete a memory region that is only accessible by the calling thread.
174 * The deleted region will be accessible by other threads.
175 *
176 * @param start is the start address of the memory region.
177 *
178 * @param size is the size of the memory region.
179 *
180 * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
181 * If the return value is any other values, it represents the operation failed.
182 */
rt_mprotect_delete_exclusive_region(void * start,rt_size_t size)183 rt_err_t rt_mprotect_delete_exclusive_region(void *start, rt_size_t size)
184 {
185 rt_uint8_t i;
186 rt_enter_critical();
187 for (i = 0; i < NUM_EXCLUSIVE_REGIONS; i++)
188 {
189 if (exclusive_regions[i].owner == rt_thread_self() && exclusive_regions[i].region.start == start && exclusive_regions[i].region.size == size)
190 {
191 exclusive_regions[i].owner = RT_NULL;
192 rt_exit_critical();
193 return RT_EOK;
194 }
195 }
196 rt_exit_critical();
197 LOG_E("Region not found");
198 return RT_ERROR;
199 }
200
201 INIT_BOARD_EXPORT(rt_mprotect_init);
202