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