Browse Source

cpu/cortexm_common: add Memory Protection Unit (MPU) driver

pr/spi.typo
Ian Martin 6 years ago
parent
commit
b7bd6b3479
  1. 163
      cpu/cortexm_common/include/mpu.h
  2. 72
      cpu/cortexm_common/mpu.c

163
cpu/cortexm_common/include/mpu.h

@ -0,0 +1,163 @@
/*
* Copyright (C) 2016 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_cortexm_common
* @{
*
* @file mpu.h
* @brief Cortex-M Memory Protection Unit (MPU) Driver Header File
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#ifndef MPU_H_
#define MPU_H_
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Number of MPU regions available (will vary depending on the Cortex-M version)
*/
#define MPU_NUM_REGIONS ( (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos )
/**
* @brief Access Permission words
*/
enum {
AP_NO_NO = 0, /**< no access for all levels */
AP_RW_NO = 1, /**< read/write for privileged level, no access from user level */
AP_RW_RO = 2, /**< read/write for privileged level, read-only for user level */
AP_RW_RW = 3, /**< read/write for all levels */
AP_RO_NO = 5, /**< read-only for privileged level, no access from user level */
AP_RO_RO = 6, /**< read-only for all levels */
};
/**
* @brief MPU region sizes
*/
enum {
MPU_SIZE_32B = 4, /**< 32 bytes */
MPU_SIZE_64B = 5, /**< 64 bytes */
MPU_SIZE_128B = 6, /**< 128 bytes */
MPU_SIZE_256B = 7, /**< 256 bytes */
MPU_SIZE_512B = 8, /**< 512 bytes */
MPU_SIZE_1K = 9, /**< 1 kilobytes */
MPU_SIZE_2K = 10, /**< 2 kilobytes */
MPU_SIZE_4K = 11, /**< 4 kilobytes */
MPU_SIZE_8K = 12, /**< 8 kilobytes */
MPU_SIZE_16K = 13, /**< 16 kilobytes */
MPU_SIZE_32K = 14, /**< 32 kilobytes */
MPU_SIZE_64K = 15, /**< 64 kilobytes */
MPU_SIZE_128K = 16, /**< 128 kilobytes */
MPU_SIZE_256K = 17, /**< 256 kilobytes */
MPU_SIZE_512K = 18, /**< 512 kilobytes */
MPU_SIZE_1M = 19, /**< 1 megabytes */
MPU_SIZE_2M = 20, /**< 2 megabytes */
MPU_SIZE_4M = 21, /**< 4 megabytes */
MPU_SIZE_8M = 22, /**< 8 megabytes */
MPU_SIZE_16M = 23, /**< 16 megabytes */
MPU_SIZE_32M = 24, /**< 32 megabytes */
MPU_SIZE_64M = 25, /**< 64 megabytes */
MPU_SIZE_128M = 26, /**< 128 megabytes */
MPU_SIZE_256M = 27, /**< 256 megabytes */
MPU_SIZE_512M = 28, /**< 512 megabytes */
MPU_SIZE_1G = 29, /**< 1 gigabytes */
MPU_SIZE_2G = 30, /**< 2 gigabytes */
MPU_SIZE_4G = 31, /**< 4 gigabytes */
};
/**
* @brief convert a region size code to a size in bytes
*
* @param[in] size region size code, e.g. MPU_SIZE_32B
*
* @return region size in bytes
*/
#define MPU_SIZE_TO_BYTES(size) ( (uintptr_t)1 << ((size) + 1) )
/**
* @brief generate an MPU attribute word suitable for writing to the RASR register
*
* @param[in] xn eXecute Never flag (forbids instruction fetches)
* @param[in] ap Access Permission word, e.g. AP_RO_RO
* @param[in] tex Type Extension Field
* @param[in] c Cacheable bit
* @param[in] b Bufferable bit
* @param[in] s Sub-Region Disable (SRD) field
* @param[in] size region size code, e.g. MPU_SIZE_32B
*
* @return combined region attribute word
*/
static inline uint32_t MPU_ATTR(
uint32_t xn,
uint32_t ap,
uint32_t tex,
uint32_t c,
uint32_t b,
uint32_t s,
uint32_t size)
{
return
(xn << 28) |
(ap << 24) |
(tex << 19) |
(s << 18) |
(c << 17) |
(b << 16) |
(size << 1);
}
/**
* @brief disable the MPU
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_disable(void);
/**
* @brief enable the MPU
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_enable(void);
/**
* @brief test if the MPU is enabled
*
* @return true if enabled
* @return false if disabled
*/
bool mpu_enabled(void);
/**
* @brief configure the base address and attributes for an MPU region
*
* @param[in] region MPU region to configure (0 <= @p region < MPU_NUM_REGIONS)
* @param[in] base base address in RAM (aligned to the size specified within @p attr)
* @param[in] attr attribute word generated by MPU_ATTR()
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_configure(uint_fast8_t region, uintptr_t base, uint_fast32_t attr);
#ifdef __cplusplus
}
#endif
#endif /* MPU_H_ */

72
cpu/cortexm_common/mpu.c

@ -0,0 +1,72 @@
/*
* Copyright (C) 2016 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_cortexm_common
* @{
*
* @file mpu.c
* @brief Cortex-M Memory Protection Unit (MPU) Driver
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "mpu.h"
int mpu_disable(void) {
#if __MPU_PRESENT
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
return 0;
#else
return -1;
#endif
}
int mpu_enable(void) {
#if __MPU_PRESENT
MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
/* Enable the memory fault exception */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
return 0;
#else
return -1;
#endif
}
bool mpu_enabled(void) {
#if __MPU_PRESENT
return (MPU->CTRL & MPU_CTRL_ENABLE_Msk) != 0;
#else
return false;
#endif
}
int mpu_configure(uint_fast8_t region, uintptr_t base, uint_fast32_t attr) {
#if __MPU_PRESENT
assert(region < MPU_NUM_REGIONS);
MPU->RNR = region;
MPU->RBAR = base & MPU_RBAR_ADDR_Msk;
MPU->RASR = attr | MPU_RASR_ENABLE_Msk;
if (!mpu_enabled()) {
mpu_enable();
}
return 0;
#else
return -1;
#endif
}
Loading…
Cancel
Save