1 //*****************************************************************************
2 //
3 // mpu.c - Driver for the Cortex-M3 memory protection unit (MPU).
4 //
5 // Copyright (c) 2007-2020 Texas Instruments Incorporated.  All rights reserved.
6 // Software License Agreement
7 //
8 //   Redistribution and use in source and binary forms, with or without
9 //   modification, are permitted provided that the following conditions
10 //   are met:
11 //
12 //   Redistributions of source code must retain the above copyright
13 //   notice, this list of conditions and the following disclaimer.
14 //
15 //   Redistributions in binary form must reproduce the above copyright
16 //   notice, this list of conditions and the following disclaimer in the
17 //   documentation and/or other materials provided with the
18 //   distribution.
19 //
20 //   Neither the name of Texas Instruments Incorporated nor the names of
21 //   its contributors may be used to endorse or promote products derived
22 //   from this software without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 //
36 // This is part of revision 2.2.0.295 of the Tiva Peripheral Driver Library.
37 //
38 //*****************************************************************************
39 
40 //*****************************************************************************
41 //
42 //! \addtogroup mpu_api
43 //! @{
44 //
45 //*****************************************************************************
46 
47 #include <stdbool.h>
48 #include <stdint.h>
49 #include "inc/hw_ints.h"
50 #include "inc/hw_nvic.h"
51 #include "inc/hw_types.h"
52 #include "driverlib/debug.h"
53 #include "driverlib/interrupt.h"
54 #include "driverlib/mpu.h"
55 
56 //*****************************************************************************
57 //
58 //! Enables and configures the MPU for use.
59 //!
60 //! \param ui32MPUConfig is the logical OR of the possible configurations.
61 //!
62 //! This function enables the Cortex-M memory protection unit.  It also
63 //! configures the default behavior when in privileged mode and while handling
64 //! a hard fault or NMI.  Prior to enabling the MPU, at least one region must
65 //! be set by calling MPURegionSet() or else by enabling the default region for
66 //! privileged mode by passing the \b MPU_CONFIG_PRIV_DEFAULT flag to
67 //! MPUEnable().  Once the MPU is enabled, a memory management fault is
68 //! generated for memory access violations.
69 //!
70 //! The \e ui32MPUConfig parameter should be the logical OR of any of the
71 //! following:
72 //!
73 //! - \b MPU_CONFIG_PRIV_DEFAULT enables the default memory map when in
74 //! privileged mode and when no other regions are defined.  If this option
75 //! is not enabled, then there must be at least one valid region already
76 //! defined when the MPU is enabled.
77 //! - \b MPU_CONFIG_HARDFLT_NMI enables the MPU while in a hard fault or NMI
78 //! exception handler.  If this option is not enabled, then the MPU is
79 //! disabled while in one of these exception handlers and the default
80 //! memory map is applied.
81 //! - \b MPU_CONFIG_NONE chooses none of the above options.  In this case,
82 //! no default memory map is provided in privileged mode, and the MPU is not
83 //! enabled in the fault handlers.
84 //!
85 //! \return None.
86 //
87 //*****************************************************************************
88 void
MPUEnable(uint32_t ui32MPUConfig)89 MPUEnable(uint32_t ui32MPUConfig)
90 {
91     //
92     // Check the arguments.
93     //
94     ASSERT(!(ui32MPUConfig & ~(MPU_CONFIG_PRIV_DEFAULT |
95                                MPU_CONFIG_HARDFLT_NMI)));
96 
97     //
98     // Set the MPU control bits according to the flags passed by the user,
99     // and also set the enable bit.
100     //
101     HWREG(NVIC_MPU_CTRL) = ui32MPUConfig | NVIC_MPU_CTRL_ENABLE;
102 }
103 
104 //*****************************************************************************
105 //
106 //! Disables the MPU for use.
107 //!
108 //! This function disables the Cortex-M memory protection unit.  When the
109 //! MPU is disabled, the default memory map is used and memory management
110 //! faults are not generated.
111 //!
112 //! \return None.
113 //
114 //*****************************************************************************
115 void
MPUDisable(void)116 MPUDisable(void)
117 {
118     //
119     // Turn off the MPU enable bit.
120     //
121     HWREG(NVIC_MPU_CTRL) &= ~NVIC_MPU_CTRL_ENABLE;
122 }
123 
124 //*****************************************************************************
125 //
126 //! Gets the count of regions supported by the MPU.
127 //!
128 //! This function is used to get the total number of regions that are supported
129 //! by the MPU, including regions that are already programmed.
130 //!
131 //! \return The number of memory protection regions that are available
132 //! for programming using MPURegionSet().
133 //
134 //*****************************************************************************
135 uint32_t
MPURegionCountGet(void)136 MPURegionCountGet(void)
137 {
138     //
139     // Read the DREGION field of the MPU type register and mask off
140     // the bits of interest to get the count of regions.
141     //
142     return((HWREG(NVIC_MPU_TYPE) & NVIC_MPU_TYPE_DREGION_M) >>
143            NVIC_MPU_TYPE_DREGION_S);
144 }
145 
146 //*****************************************************************************
147 //
148 //! Enables a specific region.
149 //!
150 //! \param ui32Region is the region number to enable.
151 //!
152 //! This function is used to enable a memory protection region.  The region
153 //! should already be configured with the MPURegionSet() function.  Once
154 //! enabled, the memory protection rules of the region are applied and access
155 //! violations cause a memory management fault.
156 //!
157 //! \return None.
158 //
159 //*****************************************************************************
160 void
MPURegionEnable(uint32_t ui32Region)161 MPURegionEnable(uint32_t ui32Region)
162 {
163     //
164     // Check the arguments.
165     //
166     ASSERT(ui32Region < 8);
167 
168     //
169     // Select the region to modify.
170     //
171     HWREG(NVIC_MPU_NUMBER) = ui32Region;
172 
173     //
174     // Modify the enable bit in the region attributes.
175     //
176     HWREG(NVIC_MPU_ATTR) |= NVIC_MPU_ATTR_ENABLE;
177 }
178 
179 //*****************************************************************************
180 //
181 //! Disables a specific region.
182 //!
183 //! \param ui32Region is the region number to disable.
184 //!
185 //! This function is used to disable a previously enabled memory protection
186 //! region.  The region remains configured if it is not overwritten with
187 //! another call to MPURegionSet(), and can be enabled again by calling
188 //! MPURegionEnable().
189 //!
190 //! \return None.
191 //
192 //*****************************************************************************
193 void
MPURegionDisable(uint32_t ui32Region)194 MPURegionDisable(uint32_t ui32Region)
195 {
196     //
197     // Check the arguments.
198     //
199     ASSERT(ui32Region < 8);
200 
201     //
202     // Select the region to modify.
203     //
204     HWREG(NVIC_MPU_NUMBER) = ui32Region;
205 
206     //
207     // Modify the enable bit in the region attributes.
208     //
209     HWREG(NVIC_MPU_ATTR) &= ~NVIC_MPU_ATTR_ENABLE;
210 }
211 
212 //*****************************************************************************
213 //
214 //! Sets up the access rules for a specific region.
215 //!
216 //! \param ui32Region is the region number to set up.
217 //! \param ui32Addr is the base address of the region.  It must be aligned
218 //! according to the size of the region specified in ui32Flags.
219 //! \param ui32Flags is a set of flags to define the attributes of the region.
220 //!
221 //! This function sets up the protection rules for a region.  The region has
222 //! a base address and a set of attributes including the size.  The base
223 //! address parameter, \e ui32Addr, must be aligned according to the size, and
224 //! the size must be a power of 2.
225 //!
226 //! The \e ui32Flags parameter is the logical OR of all of the attributes
227 //! of the region.  It is a combination of choices for region size,
228 //! execute permission, read/write permissions, disabled sub-regions,
229 //! and a flag to determine if the region is enabled.
230 //!
231 //! The size flag determines the size of a region and must be one of the
232 //! following:
233 //!
234 //! - \b MPU_RGN_SIZE_32B
235 //! - \b MPU_RGN_SIZE_64B
236 //! - \b MPU_RGN_SIZE_128B
237 //! - \b MPU_RGN_SIZE_256B
238 //! - \b MPU_RGN_SIZE_512B
239 //! - \b MPU_RGN_SIZE_1K
240 //! - \b MPU_RGN_SIZE_2K
241 //! - \b MPU_RGN_SIZE_4K
242 //! - \b MPU_RGN_SIZE_8K
243 //! - \b MPU_RGN_SIZE_16K
244 //! - \b MPU_RGN_SIZE_32K
245 //! - \b MPU_RGN_SIZE_64K
246 //! - \b MPU_RGN_SIZE_128K
247 //! - \b MPU_RGN_SIZE_256K
248 //! - \b MPU_RGN_SIZE_512K
249 //! - \b MPU_RGN_SIZE_1M
250 //! - \b MPU_RGN_SIZE_2M
251 //! - \b MPU_RGN_SIZE_4M
252 //! - \b MPU_RGN_SIZE_8M
253 //! - \b MPU_RGN_SIZE_16M
254 //! - \b MPU_RGN_SIZE_32M
255 //! - \b MPU_RGN_SIZE_64M
256 //! - \b MPU_RGN_SIZE_128M
257 //! - \b MPU_RGN_SIZE_256M
258 //! - \b MPU_RGN_SIZE_512M
259 //! - \b MPU_RGN_SIZE_1G
260 //! - \b MPU_RGN_SIZE_2G
261 //! - \b MPU_RGN_SIZE_4G
262 //!
263 //! The execute permission flag must be one of the following:
264 //!
265 //! - \b MPU_RGN_PERM_EXEC enables the region for execution of code
266 //! - \b MPU_RGN_PERM_NOEXEC disables the region for execution of code
267 //!
268 //! The read/write access permissions are applied separately for the
269 //! privileged and user modes.  The read/write access flags must be one
270 //! of the following:
271 //!
272 //! - \b MPU_RGN_PERM_PRV_NO_USR_NO - no access in privileged or user mode
273 //! - \b MPU_RGN_PERM_PRV_RW_USR_NO - privileged read/write, user no access
274 //! - \b MPU_RGN_PERM_PRV_RW_USR_RO - privileged read/write, user read-only
275 //! - \b MPU_RGN_PERM_PRV_RW_USR_RW - privileged read/write, user read/write
276 //! - \b MPU_RGN_PERM_PRV_RO_USR_NO - privileged read-only, user no access
277 //! - \b MPU_RGN_PERM_PRV_RO_USR_RO - privileged read-only, user read-only
278 //!
279 //! The region is automatically divided into 8 equally-sized sub-regions by
280 //! the MPU.  Sub-regions can only be used in regions of size 256 bytes
281 //! or larger.  Any of these 8 sub-regions can be disabled, allowing for
282 //! creation of ``holes'' in a region which can be left open, or overlaid
283 //! by another region with different attributes.  Any of the 8 sub-regions
284 //! can be disabled with a logical OR of any of the following flags:
285 //!
286 //! - \b MPU_SUB_RGN_DISABLE_0
287 //! - \b MPU_SUB_RGN_DISABLE_1
288 //! - \b MPU_SUB_RGN_DISABLE_2
289 //! - \b MPU_SUB_RGN_DISABLE_3
290 //! - \b MPU_SUB_RGN_DISABLE_4
291 //! - \b MPU_SUB_RGN_DISABLE_5
292 //! - \b MPU_SUB_RGN_DISABLE_6
293 //! - \b MPU_SUB_RGN_DISABLE_7
294 //!
295 //! Finally, the region can be initially enabled or disabled with one of
296 //! the following flags:
297 //!
298 //! - \b MPU_RGN_ENABLE
299 //! - \b MPU_RGN_DISABLE
300 //!
301 //! As an example, to set a region with the following attributes: size of
302 //! 32 KB, execution enabled, read-only for both privileged and user, one
303 //! sub-region disabled, and initially enabled; the \e ui32Flags parameter
304 //! would have the following value:
305 //!
306 //! <code>
307 //! (MPU_RGN_SIZE_32K | MPU_RGN_PERM_EXEC | MPU_RGN_PERM_PRV_RO_USR_RO |
308 //!  MPU_SUB_RGN_DISABLE_2 | MPU_RGN_ENABLE)
309 //! </code>
310 //!
311 //! \note This function writes to multiple registers and is not protected
312 //! from interrupts.  It is possible that an interrupt which accesses a
313 //! region may occur while that region is in the process of being changed.
314 //! The safest way to handle this is to disable a region before changing it.
315 //! Refer to the discussion of this in the API Detailed Description section.
316 //!
317 //! \return None.
318 //
319 //*****************************************************************************
320 void
MPURegionSet(uint32_t ui32Region,uint32_t ui32Addr,uint32_t ui32Flags)321 MPURegionSet(uint32_t ui32Region, uint32_t ui32Addr, uint32_t ui32Flags)
322 {
323     //
324     // Check the arguments.
325     //
326     ASSERT(ui32Region < 8);
327     ASSERT(ui32Addr ==
328            (ui32Addr & ~0 << (((ui32Flags & NVIC_MPU_ATTR_SIZE_M) >> 1) + 1)));
329 
330     //
331     // Program the base address, use the region field to select the
332     // region at the same time.
333     //
334     HWREG(NVIC_MPU_BASE) = ui32Addr | ui32Region | NVIC_MPU_BASE_VALID;
335 
336     //
337     // Program the region attributes.  Set the TEX field and the S, C,
338     // and B bits to fixed values that are suitable for all Tiva C and
339     // E Series memory.
340     //
341     HWREG(NVIC_MPU_ATTR) = ((ui32Flags & ~(NVIC_MPU_ATTR_TEX_M |
342                                            NVIC_MPU_ATTR_CACHEABLE)) |
343                             NVIC_MPU_ATTR_SHAREABLE | NVIC_MPU_ATTR_BUFFRABLE);
344 }
345 
346 //*****************************************************************************
347 //
348 //! Gets the current settings for a specific region.
349 //!
350 //! \param ui32Region is the region number to get.
351 //! \param pui32Addr points to storage for the base address of the region.
352 //! \param pui32Flags points to the attribute flags for the region.
353 //!
354 //! This function retrieves the configuration of a specific region.  The
355 //! meanings and format of the parameters is the same as that of the
356 //! MPURegionSet() function.
357 //!
358 //! This function can be used to save the configuration of a region for later
359 //! use with the MPURegionSet() function.  The region's enable state is
360 //! preserved in the attributes that are saved.
361 //!
362 //! \return None.
363 //
364 //*****************************************************************************
365 void
MPURegionGet(uint32_t ui32Region,uint32_t * pui32Addr,uint32_t * pui32Flags)366 MPURegionGet(uint32_t ui32Region, uint32_t *pui32Addr, uint32_t *pui32Flags)
367 {
368     //
369     // Check the arguments.
370     //
371     ASSERT(ui32Region < 8);
372     ASSERT(pui32Addr);
373     ASSERT(pui32Flags);
374 
375     //
376     // Select the region to get.
377     //
378     HWREG(NVIC_MPU_NUMBER) = ui32Region;
379 
380     //
381     // Read and store the base address for the region.
382     //
383     *pui32Addr = HWREG(NVIC_MPU_BASE) & NVIC_MPU_BASE_ADDR_M;
384 
385     //
386     // Read and store the region attributes.
387     //
388     *pui32Flags = HWREG(NVIC_MPU_ATTR);
389 }
390 
391 //*****************************************************************************
392 //
393 //! Registers an interrupt handler for the memory management fault.
394 //!
395 //! \param pfnHandler is a pointer to the function to be called when the
396 //! memory management fault occurs.
397 //!
398 //! This function sets and enables the handler to be called when the MPU
399 //! generates a memory management fault due to a protection region access
400 //! violation.
401 //!
402 //! \sa IntRegister() for important information about registering interrupt
403 //! handlers.
404 //!
405 //! \return None.
406 //
407 //*****************************************************************************
408 void
MPUIntRegister(void (* pfnHandler)(void))409 MPUIntRegister(void (*pfnHandler)(void))
410 {
411     //
412     // Check the arguments.
413     //
414     ASSERT(pfnHandler);
415 
416     //
417     // Register the interrupt handler.
418     //
419     IntRegister(FAULT_MPU, pfnHandler);
420 
421     //
422     // Enable the memory management fault.
423     //
424     IntEnable(FAULT_MPU);
425 }
426 
427 //*****************************************************************************
428 //
429 //! Unregisters an interrupt handler for the memory management fault.
430 //!
431 //! This function disables and clears the handler to be called when a
432 //! memory management fault occurs.
433 //!
434 //! \sa IntRegister() for important information about registering interrupt
435 //! handlers.
436 //!
437 //! \return None.
438 //
439 //*****************************************************************************
440 void
MPUIntUnregister(void)441 MPUIntUnregister(void)
442 {
443     //
444     // Disable the interrupt.
445     //
446     IntDisable(FAULT_MPU);
447 
448     //
449     // Unregister the interrupt handler.
450     //
451     IntUnregister(FAULT_MPU);
452 }
453 
454 //*****************************************************************************
455 //
456 // Close the Doxygen group.
457 //! @}
458 //
459 //*****************************************************************************
460