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]), &region, 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