1 /*
2  * Copyright (c) 2017 Linaro Limited.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_
7 #define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_
8 
9 #include <zephyr/types.h>
10 #include <kernel_arch_data.h>
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 #if defined(CONFIG_ARM_MPU)
17 struct k_thread;
18 
19 #if defined(CONFIG_USERSPACE)
20 
21 /**
22  * @brief Maximum number of memory domain partitions
23  *
24  * This internal macro returns the maximum number of memory partitions, which
25  * may be defined in a memory domain, given the amount of available HW MPU
26  * regions.
27  *
28  * @param mpu_regions_num the number of available HW MPU regions.
29  */
30 #if defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS) && \
31 	defined(CONFIG_MPU_GAP_FILLING)
32 /*
33  * For ARM MPU architectures, where the domain partitions cannot be defined
34  * on top of the statically configured memory regions, the maximum number of
35  * memory domain partitions is set to half of the number of available MPU
36  * regions. This ensures that in the worst-case where there are gaps between
37  * the memory partitions of the domain, the desired memory map can still be
38  * programmed using the available number of HW MPU regions.
39  */
40 #define ARM_CORE_MPU_MAX_DOMAIN_PARTITIONS_GET(mpu_regions_num) \
41 	(mpu_regions_num/2)
42 #else
43 /*
44  * For ARM MPU architectures, where the domain partitions can be defined
45  * on top of the statically configured memory regions, the maximum number
46  * of memory domain partitions is equal to the number of available MPU regions.
47  */
48 #define ARM_CORE_MPU_MAX_DOMAIN_PARTITIONS_GET(mpu_regions_num) \
49 	(mpu_regions_num)
50 #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS */
51 
52 /**
53  * @brief Maximum number of MPU regions required to configure a
54  *        memory region for (user) Thread Stack.
55  */
56 #if defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS) && \
57 	defined(CONFIG_MPU_GAP_FILLING)
58 /* When dynamic regions may not be defined on top of statically
59  * allocated memory regions, defining a region for a thread stack
60  * requires two additional MPU regions to be configured; one for
61  * defining the thread stack and an additional one for partitioning
62  * the underlying memory area.
63  */
64 #define ARM_CORE_MPU_NUM_MPU_REGIONS_FOR_THREAD_STACK 2
65 #else
66 /* When dynamic regions may be defined on top of statically allocated
67  * memory regions, a thread stack area may be configured using a
68  * single MPU region.
69  */
70 #define ARM_CORE_MPU_NUM_MPU_REGIONS_FOR_THREAD_STACK 1
71 #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS */
72 
73 /**
74  * @brief Maximum number of MPU regions required to configure a
75  *        memory region for a (supervisor) Thread Stack Guard.
76  */
77 #if (defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS) && \
78 		defined(CONFIG_MPU_GAP_FILLING)) \
79 	|| defined(CONFIG_CPU_HAS_NXP_SYSMPU)
80 /*
81  * When dynamic regions may not be defined on top of statically
82  * allocated memory regions, defining a region for a supervisor
83  * thread stack guard requires two additional MPU regions to be
84  * configured; one for defining the stack guard and an additional
85  * one for partitioning the underlying memory area.
86  *
87  * The same is required for the NXP MPU due to its OR-based decision
88  * policy; the MPU stack guard applies more restrictive permissions on
89  * the underlying (SRAM) regions, and, therefore, we need to partition
90  * the underlying SRAM region.
91  */
92 #define ARM_CORE_MPU_NUM_MPU_REGIONS_FOR_MPU_STACK_GUARD 2
93 #elif defined(CONFIG_CPU_HAS_ARM_MPU)
94 /* When dynamic regions may be defined on top of statically allocated
95  * memory regions, a supervisor thread stack guard area may be configured
96  * using a single MPU region.
97  */
98 #define ARM_CORE_MPU_NUM_MPU_REGIONS_FOR_MPU_STACK_GUARD 1
99 #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS || CPU_HAS_NXP_SYSMPU */
100 
101 #endif /* CONFIG_USERSPACE */
102 
103 
104 /* ARM Core MPU Driver API */
105 
106 /*
107  * This API has to be implemented by all the MPU drivers that have
108  * ARM_MPU support.
109  */
110 
111 /**
112  * @brief configure a set of fixed (static) MPU regions
113  *
114  * Internal API function to configure a set of static MPU memory regions,
115  * within a (background) memory area determined by start and end address.
116  * The total number of HW MPU regions to be programmed depends on the MPU
117  * architecture.
118  *
119  * The function shall be invoked once, upon system initialization.
120  *
121  * @param static_regions an array of pointers to memory partitions
122  *                       to be programmed
123  * @param regions_num the number of regions to be programmed
124  * @param background_area_start the start address of the background memory area
125  * @param background_area_end the end address of the background memory area
126  *
127  * The function shall assert if the operation cannot be not performed
128  * successfully. Therefore:
129  * - the number of HW MPU regions to be programmed shall not exceed the number
130  *   of available MPU indices,
131  * - the size and alignment of the static regions shall comply with the
132  *   requirements of the MPU hardware.
133  */
134 void arm_core_mpu_configure_static_mpu_regions(
135 	const struct z_arm_mpu_partition *static_regions,
136 	const uint8_t regions_num, const uint32_t background_area_start,
137 	const uint32_t background_area_end);
138 
139 #if defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS)
140 
141 /* Number of memory areas, inside which dynamic regions
142  * may be programmed in run-time.
143  */
144 #define MPU_DYNAMIC_REGION_AREAS_NUM 1
145 
146 /**
147  * @brief mark a set of memory regions as eligible for dynamic configuration
148  *
149  * Internal API function to configure a set of memory regions, determined
150  * by their start address and size, as memory areas eligible for dynamically
151  * programming MPU regions (such as a supervisor stack overflow guard) at
152  * run-time (for example, thread upon context-switch).
153  *
154  * The function shall be invoked once, upon system initialization.
155  *
156  * @param dyn_region_areas an array of z_arm_mpu_partition objects declaring the
157  *                             eligible memory areas for dynamic programming
158  * @param dyn_region_areas_num the number of eligible areas for dynamic
159  *                             programming.
160  *
161  * The function shall assert if the operation cannot be not performed
162  * successfully. Therefore, the requested areas shall correspond to
163  * static memory regions, configured earlier by
164  * arm_core_mpu_configure_static_mpu_regions().
165  */
166 void arm_core_mpu_mark_areas_for_dynamic_regions(
167 	const struct z_arm_mpu_partition *dyn_region_areas,
168 	const uint8_t dyn_region_areas_num);
169 
170 #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS */
171 
172 /**
173  * @brief configure a set of dynamic MPU regions
174  *
175  * Internal API function to configure a set of dynamic MPU memory regions
176  * within a (background) memory area. The total number of HW MPU regions
177  * to be programmed depends on the MPU architecture.
178  *
179  * @param dynamic_regions an array of pointers to memory partitions
180  *                        to be programmed
181  * @param regions_num the number of regions to be programmed
182  *
183  * The function shall assert if the operation cannot be not performed
184  * successfully. Therefore, the number of HW MPU regions to be programmed shall
185  * not exceed the number of (currently) available MPU indices.
186  */
187 void arm_core_mpu_configure_dynamic_mpu_regions(
188 	const struct z_arm_mpu_partition *dynamic_regions,
189 	uint8_t regions_num);
190 
191 #if defined(CONFIG_USERSPACE)
192 /**
193  * @brief update configuration of an active memory partition
194  *
195  * Internal API function to re-configure the access permissions of an
196  * active memory partition, i.e. a partition that has earlier been
197  * configured in the (current) thread context.
198  *
199  * @param partition Pointer to a structure holding the partition information
200  *                  (must be valid).
201  * @param new_attr  New access permissions attribute for the partition.
202  *
203  * The function shall assert if the operation cannot be not performed
204  * successfully (e.g. the given partition can not be found).
205  */
206 void arm_core_mpu_mem_partition_config_update(
207 	struct z_arm_mpu_partition *partition,
208 	k_mem_partition_attr_t *new_attr);
209 
210 #endif /* CONFIG_USERSPACE */
211 
212 /**
213  * @brief configure the base address and size for an MPU region
214  *
215  * @param   type    MPU region type
216  * @param   base    base address in RAM
217  * @param   size    size of the region
218  */
219 void arm_core_mpu_configure(uint8_t type, uint32_t base, uint32_t size);
220 
221 /**
222  * @brief configure MPU regions for the memory partitions of the memory domain
223  *
224  * @param   mem_domain    memory domain that thread belongs to
225  */
226 void arm_core_mpu_configure_mem_domain(struct k_mem_domain *mem_domain);
227 
228 /**
229  * @brief configure MPU regions for a user thread's context
230  *
231  * @param	thread	thread to configure
232  */
233 void arm_core_mpu_configure_user_context(struct k_thread *thread);
234 
235 /**
236  * @brief configure MPU region for a single memory partition
237  *
238  * @param   part_index  memory partition index
239  * @param   part        memory partition info
240  */
241 void arm_core_mpu_configure_mem_partition(uint32_t part_index,
242 					  struct z_arm_mpu_partition *part);
243 
244 /**
245  * @brief Reset MPU region for a single memory partition
246  *
247  * @param   part_index  memory partition index
248  */
249 void arm_core_mpu_mem_partition_remove(uint32_t part_index);
250 
251 /**
252  * @brief Get the maximum number of available (free) MPU region indices
253  *        for configuring dynamic MPU regions.
254  */
255 int arm_core_mpu_get_max_available_dyn_regions(void);
256 
257 /**
258  * @brief validate the given buffer is user accessible or not
259  *
260  * Note: Validation will always return failure, if the supplied buffer
261  *       spans multiple enabled MPU regions (even if these regions all
262  *       permit user access).
263  */
264 int arm_core_mpu_buffer_validate(const void *addr, size_t size, int write);
265 
266 #endif /* CONFIG_ARM_MPU */
267 
268 #ifdef __cplusplus
269 }
270 #endif
271 
272 #endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ */
273