447 lines
15 KiB
C
447 lines
15 KiB
C
//*****************************************************************************
|
|
//
|
|
// mpu.c - Driver for the Cortex-M3 memory protection unit (MPU).
|
|
//
|
|
// Copyright (c) 2007-2010 Texas Instruments Incorporated. All rights reserved.
|
|
// Software License Agreement
|
|
//
|
|
// Texas Instruments (TI) is supplying this software for use solely and
|
|
// exclusively on TI's microcontroller products. The software is owned by
|
|
// TI and/or its suppliers, and is protected under applicable copyright
|
|
// laws. You may not combine this software with "viral" open-source
|
|
// software in order to form a larger program.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
|
|
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
|
|
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
|
|
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
|
|
// DAMAGES, FOR ANY REASON WHATSOEVER.
|
|
//
|
|
// This is part of revision 6459 of the Stellaris Peripheral Driver Library.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! \addtogroup mpu_api
|
|
//! @{
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "inc/hw_ints.h"
|
|
#include "inc/hw_nvic.h"
|
|
#include "inc/hw_types.h"
|
|
#include "driverlib/debug.h"
|
|
#include "driverlib/interrupt.h"
|
|
#include "driverlib/mpu.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Enables and configures the MPU for use.
|
|
//!
|
|
//! \param ulMPUConfig is the logical OR of the possible configurations.
|
|
//!
|
|
//! This function enables the Cortex-M3 memory protection unit. It also
|
|
//! configures the default behavior when in privileged mode and while
|
|
//! handling a hard fault or NMI. Prior to enabling the MPU, at least one
|
|
//! region must be set by calling MPURegionSet() or else by enabling the
|
|
//! default region for privileged mode by passing the
|
|
//! \b MPU_CONFIG_PRIV_DEFAULT flag to MPUEnable().
|
|
//! Once the MPU is enabled, a memory management fault will be generated
|
|
//! for any memory access violations.
|
|
//!
|
|
//! The \e ulMPUConfig parameter should be the logical OR of any of the
|
|
//! following:
|
|
//!
|
|
//! - \b MPU_CONFIG_PRIV_DEFAULT enables the default memory map when in
|
|
//! privileged mode and when no other regions are defined. If this option
|
|
//! is not enabled, then there must be at least one valid region already
|
|
//! defined when the MPU is enabled.
|
|
//! - \b MPU_CONFIG_HARDFLT_NMI enables the MPU while in a hard fault or NMI
|
|
//! exception handler. If this option is not enabled, then the MPU is
|
|
//! disabled while in one of these exception handlers and the default
|
|
//! memory map is applied.
|
|
//! - \b MPU_CONFIG_NONE chooses none of the above options. In this case,
|
|
//! no default memory map is provided in privileged mode, and the MPU will
|
|
//! not be enabled in the fault handlers.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPUEnable(unsigned long ulMPUConfig)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(!(ulMPUConfig & ~(MPU_CONFIG_PRIV_DEFAULT |
|
|
MPU_CONFIG_HARDFLT_NMI)));
|
|
|
|
//
|
|
// Set the MPU control bits according to the flags passed by the user,
|
|
// and also set the enable bit.
|
|
//
|
|
HWREG(NVIC_MPU_CTRL) = ulMPUConfig | NVIC_MPU_CTRL_ENABLE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Disables the MPU for use.
|
|
//!
|
|
//! This function disables the Cortex-M3 memory protection unit. When the
|
|
//! MPU is disabled, the default memory map is used and memory management
|
|
//! faults are not generated.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPUDisable(void)
|
|
{
|
|
//
|
|
// Turn off the MPU enable bit.
|
|
//
|
|
HWREG(NVIC_MPU_CTRL) &= ~NVIC_MPU_CTRL_ENABLE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Gets the count of regions supported by the MPU.
|
|
//!
|
|
//! This function is used to get the number of regions that are supported by
|
|
//! the MPU. This is the total number that are supported, including regions
|
|
//! that are already programmed.
|
|
//!
|
|
//! \return The number of memory protection regions that are available
|
|
//! for programming using MPURegionSet().
|
|
//
|
|
//*****************************************************************************
|
|
unsigned long
|
|
MPURegionCountGet(void)
|
|
{
|
|
//
|
|
// Read the DREGION field of the MPU type register, and mask off
|
|
// the bits of interest to get the count of regions.
|
|
//
|
|
return((HWREG(NVIC_MPU_TYPE) & NVIC_MPU_TYPE_DREGION_M)
|
|
>> NVIC_MPU_TYPE_DREGION_S);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Enables a specific region.
|
|
//!
|
|
//! \param ulRegion is the region number to enable.
|
|
//!
|
|
//! This function is used to enable a memory protection region. The region
|
|
//! should already be set up with the MPURegionSet() function. Once enabled,
|
|
//! the memory protection rules of the region will be applied and access
|
|
//! violations will cause a memory management fault.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPURegionEnable(unsigned long ulRegion)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(ulRegion < 8);
|
|
|
|
//
|
|
// Select the region to modify.
|
|
//
|
|
HWREG(NVIC_MPU_NUMBER) = ulRegion;
|
|
|
|
//
|
|
// Modify the enable bit in the region attributes.
|
|
//
|
|
HWREG(NVIC_MPU_ATTR) |= NVIC_MPU_ATTR_ENABLE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Disables a specific region.
|
|
//!
|
|
//! \param ulRegion is the region number to disable.
|
|
//!
|
|
//! This function is used to disable a previously enabled memory protection
|
|
//! region. The region will remain configured if it is not overwritten with
|
|
//! another call to MPURegionSet(), and can be enabled again by calling
|
|
//! MPURegionEnable().
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPURegionDisable(unsigned long ulRegion)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(ulRegion < 8);
|
|
|
|
//
|
|
// Select the region to modify.
|
|
//
|
|
HWREG(NVIC_MPU_NUMBER) = ulRegion;
|
|
|
|
//
|
|
// Modify the enable bit in the region attributes.
|
|
//
|
|
HWREG(NVIC_MPU_ATTR) &= ~NVIC_MPU_ATTR_ENABLE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Sets up the access rules for a specific region.
|
|
//!
|
|
//! \param ulRegion is the region number to set up.
|
|
//! \param ulAddr is the base address of the region. It must be aligned
|
|
//! according to the size of the region specified in ulFlags.
|
|
//! \param ulFlags is a set of flags to define the attributes of the region.
|
|
//!
|
|
//! This function sets up the protection rules for a region. The region has
|
|
//! a base address and a set of attributes including the size, which must
|
|
//! be a power of 2. The base address parameter, \e ulAddr, must be aligned
|
|
//! according to the size.
|
|
//!
|
|
//! The \e ulFlags parameter is the logical OR of all of the attributes
|
|
//! of the region. It is a combination of choices for region size,
|
|
//! execute permission, read/write permissions, disabled sub-regions,
|
|
//! and a flag to determine if the region is enabled.
|
|
//!
|
|
//! The size flag determines the size of a region, and must be one of the
|
|
//! following:
|
|
//!
|
|
//! - \b MPU_RGN_SIZE_32B
|
|
//! - \b MPU_RGN_SIZE_64B
|
|
//! - \b MPU_RGN_SIZE_128B
|
|
//! - \b MPU_RGN_SIZE_256B
|
|
//! - \b MPU_RGN_SIZE_512B
|
|
//! - \b MPU_RGN_SIZE_1K
|
|
//! - \b MPU_RGN_SIZE_2K
|
|
//! - \b MPU_RGN_SIZE_4K
|
|
//! - \b MPU_RGN_SIZE_8K
|
|
//! - \b MPU_RGN_SIZE_16K
|
|
//! - \b MPU_RGN_SIZE_32K
|
|
//! - \b MPU_RGN_SIZE_64K
|
|
//! - \b MPU_RGN_SIZE_128K
|
|
//! - \b MPU_RGN_SIZE_256K
|
|
//! - \b MPU_RGN_SIZE_512K
|
|
//! - \b MPU_RGN_SIZE_1M
|
|
//! - \b MPU_RGN_SIZE_2M
|
|
//! - \b MPU_RGN_SIZE_4M
|
|
//! - \b MPU_RGN_SIZE_8M
|
|
//! - \b MPU_RGN_SIZE_16M
|
|
//! - \b MPU_RGN_SIZE_32M
|
|
//! - \b MPU_RGN_SIZE_64M
|
|
//! - \b MPU_RGN_SIZE_128M
|
|
//! - \b MPU_RGN_SIZE_256M
|
|
//! - \b MPU_RGN_SIZE_512M
|
|
//! - \b MPU_RGN_SIZE_1G
|
|
//! - \b MPU_RGN_SIZE_2G
|
|
//! - \b MPU_RGN_SIZE_4G
|
|
//!
|
|
//! The execute permission flag must be one of the following:
|
|
//!
|
|
//! - \b MPU_RGN_PERM_EXEC enables the region for execution of code
|
|
//! - \b MPU_RGN_PERM_NOEXEC disables the region for execution of code
|
|
//!
|
|
//! The read/write access permissions are applied separately for the
|
|
//! privileged and user modes. The read/write access flags must be one
|
|
//! of the following:
|
|
//!
|
|
//! - \b MPU_RGN_PERM_PRV_NO_USR_NO - no access in privileged or user mode
|
|
//! - \b MPU_RGN_PERM_PRV_RW_USR_NO - privileged read/write, user no access
|
|
//! - \b MPU_RGN_PERM_PRV_RW_USR_RO - privileged read/write, user read-only
|
|
//! - \b MPU_RGN_PERM_PRV_RW_USR_RW - privileged read/write, user read/write
|
|
//! - \b MPU_RGN_PERM_PRV_RO_USR_NO - privileged read-only, user no access
|
|
//! - \b MPU_RGN_PERM_PRV_RO_USR_RO - privileged read-only, user read-only
|
|
//!
|
|
//! The region is automatically divided into 8 equally-sized sub-regions by
|
|
//! the MPU. Sub-regions can only be used in regions of size 256 bytes
|
|
//! or larger. Any of these 8 sub-regions can be disabled. This allows
|
|
//! for creation of ``holes'' in a region which can be left open, or overlaid
|
|
//! by another region with different attributes. Any of the 8 sub-regions
|
|
//! can be disabled with a logical OR of any of the following flags:
|
|
//!
|
|
//! - \b MPU_SUB_RGN_DISABLE_0
|
|
//! - \b MPU_SUB_RGN_DISABLE_1
|
|
//! - \b MPU_SUB_RGN_DISABLE_2
|
|
//! - \b MPU_SUB_RGN_DISABLE_3
|
|
//! - \b MPU_SUB_RGN_DISABLE_4
|
|
//! - \b MPU_SUB_RGN_DISABLE_5
|
|
//! - \b MPU_SUB_RGN_DISABLE_6
|
|
//! - \b MPU_SUB_RGN_DISABLE_7
|
|
//!
|
|
//! Finally, the region can be initially enabled or disabled with one of
|
|
//! the following flags:
|
|
//!
|
|
//! - \b MPU_RGN_ENABLE
|
|
//! - \b MPU_RGN_DISABLE
|
|
//!
|
|
//! As an example, to set a region with the following attributes: size of
|
|
//! 32 KB, execution enabled, read-only for both privileged and user, one
|
|
//! sub-region disabled, and initially enabled; the \e ulFlags parameter would
|
|
//! have the following value:
|
|
//!
|
|
//! <code>
|
|
//! (MPU_RG_SIZE_32K | MPU_RGN_PERM_EXEC | MPU_RGN_PERM_PRV_RO_USR_RO |
|
|
//! MPU_SUB_RGN_DISABLE_2 | MPU_RGN_ENABLE)
|
|
//! </code>
|
|
//!
|
|
//! \note This function will write to multiple registers and is not protected
|
|
//! from interrupts. It is possible that an interrupt which accesses a
|
|
//! region may occur while that region is in the process of being changed.
|
|
//! The safest way to handle this is to disable a region before changing it.
|
|
//! Refer to the discussion of this in the API Detailed Description section.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPURegionSet(unsigned long ulRegion, unsigned long ulAddr,
|
|
unsigned long ulFlags)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(ulRegion < 8);
|
|
ASSERT((ulAddr & ~0 << (((ulFlags & NVIC_MPU_ATTR_SIZE_M) >> 1) + 1))
|
|
== ulAddr);
|
|
|
|
//
|
|
// Program the base address, use the region field to select the
|
|
// region at the same time.
|
|
//
|
|
HWREG(NVIC_MPU_BASE) = ulAddr | ulRegion | NVIC_MPU_BASE_VALID;
|
|
|
|
//
|
|
// Program the region attributes. Set the TEX field and the S, C,
|
|
// and B bits to fixed values that are suitable for all Stellaris
|
|
// memory.
|
|
//
|
|
HWREG(NVIC_MPU_ATTR) = (ulFlags & ~(NVIC_MPU_ATTR_TEX_M |
|
|
NVIC_MPU_ATTR_CACHEABLE)) |
|
|
NVIC_MPU_ATTR_SHAREABLE |
|
|
NVIC_MPU_ATTR_BUFFRABLE;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Gets the current settings for a specific region.
|
|
//!
|
|
//! \param ulRegion is the region number to get.
|
|
//! \param pulAddr points to storage for the base address of the region.
|
|
//! \param pulFlags points to the attribute flags for the region.
|
|
//!
|
|
//! This function retrieves the configuration of a specific region. The
|
|
//! meanings and format of the parameters is the same as that of the
|
|
//! MPURegionSet() function.
|
|
//!
|
|
//! This function can be used to save the configuration of a region for
|
|
//! later use with the MPURegionSet() function. The region's enable state
|
|
//! will be preserved in the attributes that are saved.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPURegionGet(unsigned long ulRegion, unsigned long *pulAddr,
|
|
unsigned long *pulFlags)
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(ulRegion < 8);
|
|
ASSERT(pulAddr);
|
|
ASSERT(pulFlags);
|
|
|
|
//
|
|
// Select the region to get.
|
|
//
|
|
HWREG(NVIC_MPU_NUMBER) = ulRegion;
|
|
|
|
//
|
|
// Read and store the base address for the region.
|
|
//
|
|
*pulAddr = HWREG(NVIC_MPU_BASE);
|
|
|
|
//
|
|
// Read and store the region attributes.
|
|
//
|
|
*pulFlags = HWREG(NVIC_MPU_ATTR);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Registers an interrupt handler for the memory management fault.
|
|
//!
|
|
//! \param pfnHandler is a pointer to the function to be called when the
|
|
//! memory management fault occurs.
|
|
//!
|
|
//! This sets and enables the handler to be called when the MPU generates
|
|
//! a memory management fault due to a protection region access violation.
|
|
//!
|
|
//! \sa IntRegister() for important information about registering interrupt
|
|
//! handlers.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPUIntRegister(void (*pfnHandler)(void))
|
|
{
|
|
//
|
|
// Check the arguments.
|
|
//
|
|
ASSERT(pfnHandler);
|
|
|
|
//
|
|
// Register the interrupt handler.
|
|
//
|
|
IntRegister(FAULT_MPU, pfnHandler);
|
|
|
|
//
|
|
// Enable the memory management fault.
|
|
//
|
|
IntEnable(FAULT_MPU);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Unregisters an interrupt handler for the memory management fault.
|
|
//!
|
|
//! This function will disable and clear the handler to be called when a
|
|
//! memory management fault occurs.
|
|
//!
|
|
//! \sa IntRegister() for important information about registering interrupt
|
|
//! handlers.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
MPUIntUnregister(void)
|
|
{
|
|
//
|
|
// Disable the interrupt.
|
|
//
|
|
IntDisable(FAULT_MPU);
|
|
|
|
//
|
|
// Unregister the interrupt handler.
|
|
//
|
|
IntUnregister(FAULT_MPU);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Close the Doxygen group.
|
|
//! @}
|
|
//
|
|
//*****************************************************************************
|