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