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