6448c509创建于 4月21日历史提交
/****************************************************************************
 * arch/arm/src/armv7-m/mpu.h
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __ARCH_ARM_SRC_ARMV7_M_MPU_H
#define __ARCH_ARM_SRC_ARMV7_M_MPU_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#ifndef __ASSEMBLY__
#  include <sys/types.h>
#  include <stdint.h>
#  include <stdbool.h>
#  include <assert.h>
#  include <debug.h>
#endif

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* MPU Register Addresses */

#define MPU_TYPE                0xe000ed90 /* MPU Type Register */
#define MPU_CTRL                0xe000ed94 /* MPU Control Register */
#define MPU_RNR                 0xe000ed98 /* MPU Region Number Register */
#define MPU_RBAR                0xe000ed9c /* MPU Region Base Address Register */
#define MPU_RASR                0xe000eda0 /* MPU Region Attribute and Size Register */

#define MPU_RBAR_A1             0xe000eda4 /* MPU alias registers */
#define MPU_RASR_A1             0xe000eda8
#define MPU_RBAR_A2             0xe000edac
#define MPU_RASR_A2             0xe000edb0
#define MPU_RBAR_A3             0xe000edb4
#define MPU_RASR_A3             0xe000edb8

/* MPU Type Register Bit Definitions */

#define MPU_TYPE_SEPARATE       (1 << 0) /* Bit 0: 0:unified or 1:separate memory maps */
#define MPU_TYPE_DREGION_SHIFT  (8)      /* Bits 8-15: Number MPU data regions */
#define MPU_TYPE_DREGION_MASK   (0xff << MPU_TYPE_DREGION_SHIFT)
#define MPU_TYPE_IREGION_SHIFT  (16)     /* Bits 16-23: Number MPU instruction regions */
#define MPU_TYPE_IREGION_MASK   (0xff << MPU_TYPE_IREGION_SHIFT)

/* MPU Control Register Bit Definitions */

#define MPU_CTRL_ENABLE         (1 << 0)  /* Bit 0: Enable the MPU */
#define MPU_CTRL_HFNMIENA       (1 << 1)  /* Bit 1: Enable MPU during hard fault, NMI, and FAULTMAS */
#define MPU_CTRL_PRIVDEFENA     (1 << 2)  /* Bit 2: Enable privileged access to default memory map */

/* MPU Region Number Register Bit Definitions */

#if defined(CONFIG_ARM_MPU_NREGIONS) && defined(CONFIG_ARM_MPU)
#  if CONFIG_ARM_MPU_NREGIONS <= 8
#    define MPU_RNR_MASK        (0x00000007)
#  elif CONFIG_ARM_MPU_NREGIONS <= 16
#    define MPU_RNR_MASK        (0x0000000f)
#  elif CONFIG_ARM_MPU_NREGIONS <= 32
#    define MPU_RNR_MASK        (0x0000001f)
#  else
#    error "FIXME: Unsupported number of MPU regions"
#  endif
#endif

/* MPU Region Base Address Register Bit Definitions */

#define MPU_RBAR_REGION_SHIFT   (0)                         /* Bits 0-3: MPU region */
#define MPU_RBAR_REGION_MASK    (15 << MPU_RBAR_REGION_SHIFT)
#define MPU_RBAR_VALID          (1 << 4)                    /* Bit 4: MPU Region Number valid */
#define MPU_RBAR_ADDR_MASK      0xffffffe0                  /* Bits N-31:  Region base addrese */

/* MPU Region Attributes and Size Register Bit Definitions */

#define MPU_RASR_ENABLE         (1 << 0)                   /* Bit 0: Region enable */
#define MPU_RASR_SIZE_SHIFT     (1)                        /* Bits 1-5: Size of the MPU protection region */
#define MPU_RASR_SIZE_MASK      (31 << MPU_RASR_SIZE_SHIFT)
#  define MPU_RASR_SIZE_LOG2(n) ((n - 1) << MPU_RASR_SIZE_SHIFT)
#define MPU_RASR_SRD_SHIFT      (8)                        /* Bits 8-15: Subregion disable */
#define MPU_RASR_SRD_MASK       (0xff << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_0        (0x01 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_1        (0x02 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_2        (0x04 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_3        (0x08 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_4        (0x10 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_5        (0x20 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_6        (0x40 << MPU_RASR_SRD_SHIFT)
#  define MPU_RASR_SRD_7        (0x80 << MPU_RASR_SRD_SHIFT)
#define MPU_RASR_ATTR_SHIFT     (16)                       /* Bits 16-31: MPU Region Attribute field */
#define MPU_RASR_ATTR_MASK      (0xffff << MPU_RASR_ATTR_SHIFT)
#  define MPU_RASR_B            (1 << 16)                  /* Bit 16: Bufferable */
#  define MPU_RASR_C            (1 << 17)                  /* Bit 17: Cacheable */
#  define MPU_RASR_S            (1 << 18)                  /* Bit 18: Shareable */
#  define MPU_RASR_TEX_SHIFT    (19)                       /* Bits 19-21: TEX Address Permission */
#  define MPU_RASR_TEX_MASK     (7 << MPU_RASR_TEX_SHIFT)
#    define MPU_RASR_TEX_SO     (0 << MPU_RASR_TEX_SHIFT) /* Strongly Ordered */
#    define MPU_RASR_TEX_NOR    (1 << MPU_RASR_TEX_SHIFT) /* Normal           */
#    define MPU_RASR_TEX_DEV    (2 << MPU_RASR_TEX_SHIFT) /* Device           */
#    define MPU_RASR_TEX_BB(bb) ((4 | (bb)) << MPU_RASR_TEX_SHIFT)
#      define MPU_RASR_CP_NC    (0)                       /* Non-cacheable */
#      define MPU_RASR_CP_WBRA  (1)                       /* Write back, write and Read- Allocate */
#      define MPU_RASR_CP_WT    (2)                       /* Write through, no Write-Allocate */
#      define MPU_RASR_CP_WB    (4)                       /* Write back, no Write-Allocate */
#  define MPU_RASR_AP_SHIFT     (24)                      /* Bits 24-26: Access permission */
#  define MPU_RASR_AP_MASK      (7 << MPU_RASR_AP_SHIFT)
#    define MPU_RASR_AP_NONO    (0 << MPU_RASR_AP_SHIFT)  /* P:None U:None */
#    define MPU_RASR_AP_RWNO    (1 << MPU_RASR_AP_SHIFT)  /* P:RW   U:None */
#    define MPU_RASR_AP_RWRO    (2 << MPU_RASR_AP_SHIFT)  /* P:RW   U:RO   */
#    define MPU_RASR_AP_RWRW    (3 << MPU_RASR_AP_SHIFT)  /* P:RW   U:RW   */
#    define MPU_RASR_AP_RONO    (5 << MPU_RASR_AP_SHIFT)  /* P:RO   U:None */
#    define MPU_RASR_AP_RORO    (6 << MPU_RASR_AP_SHIFT)  /* P:RO   U:RO   */
#  define MPU_RASR_XN           (1 << 28)                 /* Bit 28: Instruction access disable */

struct mpu_region_s
{
  /* Region Base Address */

  uintptr_t base;

  /* Region Size */

  size_t size;

  /* Region Attributes */

  uint32_t flags;
};

/****************************************************************************
 * Name: mpu_reset
 *
 * Description:
 *   Conditional public interface that resets the MPU to disabled during
 *   MPU initialization.
 *
 * Input Parameters:
 *   None.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

#if defined(CONFIG_ARM_MPU_RESET)
void mpu_reset(void);
#else
#  define mpu_reset()
#endif

/****************************************************************************
 * Name: mpu_early_reset
 *
 * Description:
 *   Conditional public interface that resets the MPU to disabled immediately
 *   after reset.
 *
 * Input Parameters:
 *   None.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

#if defined(CONFIG_ARM_MPU_EARLY_RESET)
void mpu_early_reset(void);
#else
#  define mpu_early_reset()
#endif

#ifdef CONFIG_ARM_MPU

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Name: mpu_allocregions
 *
 * Description:
 *   Allocate the regions
 *
 * Input Parameters:
 *   nregions - The number of regions to be allocated.
 *
 * Returned Value:
 *   The index of the allocated region.
 *
 ****************************************************************************/

unsigned int mpu_allocregions(unsigned int nregions);

/****************************************************************************
 * Name: mpu_allocregion
 *
 * Description:
 *   Allocate the next region
 *
 * Input Parameters:
 *   None
 *
 * Returned Value:
 *   The index of the allocated region.
 *
 ****************************************************************************/

#define mpu_allocregion() mpu_allocregions(1)

/****************************************************************************
 * Name: mpu_freeregion
 *
 * Description:
 *   Free target region.
 *
 * Input Parameters:
 *  region - The index of the region to be freed.
 *
 * Returned Value:
 *   None
 *
 ****************************************************************************/

void mpu_freeregion(unsigned int region);

/****************************************************************************
 * Name: mpu_log2regionceil
 *
 * Description:
 *   Determine the smallest value of l2size (log base 2 size) such that the
 *   following is true:
 *
 *   size <= (1 << l2size)
 *
 * Input Parameters:
 *   size - The size of the region.
 *
 * Returned Value:
 *   The logarithm base 2 of the ceiling value for the MPU region size.
 *
 ****************************************************************************/

uint8_t mpu_log2regionceil(size_t size);

/****************************************************************************
 * Name: mpu_log2regionfloor
 *
 * Description:
 *   Determine the largest value of l2size (log base 2 size) such that the
 *   following is true:
 *
 *   size >= (1 << l2size)
 *
 * Input Parameters:
 *   size - The size of the region.
 *
 * Returned Value:
 *   The logarithm base 2 of the floor value for the MPU region size.
 *
 ****************************************************************************/

uint8_t mpu_log2regionfloor(size_t size);

/****************************************************************************
 * Name: mpu_subregion
 *
 * Description:
 *   Given the size of the (1) memory to be mapped and (2) the log2 size
 *   of the mapping to use, determine the minimal sub-region set to span
 *   that memory region.
 *
 * Assumption:
 *   l2size has the same properties as the return value from
 *   mpu_log2regionceil()
 *
 * Input Parameters:
 *   base   - The base address of the region.
 *   size   - The size of the region.
 *   l2size - Log2 of the actual region size is <= (1 << l2size).
 *
 * Returned Value:
 *   The subregion settings as a 32-bit value.
 *
 ****************************************************************************/

uint32_t mpu_subregion(uintptr_t base, size_t size, uint8_t l2size);

/****************************************************************************
 * Name: mpu_control
 *
 * Description:
 *   Configure and enable (or disable) the MPU
 *
 * Input Parameters:
 *   enable     - Flag indicating whether to enable the MPU.
 *   hfnmiena   - Flag indicating whether to enable the MPU during hard
 *                fult, NMI, and FAULTMAS.
 *   privdefena - Flag indicating whether to enable privileged access to
 *                the default memory map.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

void mpu_control(bool enable, bool hfnmiena, bool privdefena);

/****************************************************************************
 * Name: mpu_dump_region
 *
 * Description:
 *   Dump the region that has been used.
 *
 * Input Parameters:
 *   None.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

void mpu_dump_region(void);

/****************************************************************************
 * Name: mpu_modify_region
 *
 * Description:
 *   Modify a region for privileged, strongly ordered memory
 *
 * Input Parameters:
 *   region - Region number to modify.
 *   base   - Base address of the region.
 *   size   - Size of the region.
 *   flags  - Flags to configure the region.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

void mpu_modify_region(unsigned int region, uintptr_t base, size_t size,
                       uint32_t flags);

/****************************************************************************
 * Name: mpu_modify_regions
 *
 * Description:
 *   Configure multi regions for privileged, strongly ordered memory
 *
 * Input Parameters:
 *   region  - First region number to modify.
 *   base    - Base address of the region.
 *   size    - Size of the region.
 *   flags   - Flags to configure the region.
 *
 ****************************************************************************/

void mpu_modify_regions(unsigned int region, uintptr_t base, size_t size,
                        uint32_t flags);

/****************************************************************************
 * Name: mpu_enable_region
 *
 * Description:
 *   Contrl a region enable or disable
 *
 * Input Parameters:
 *   region - The index of the MPU region to modify.
 *   enable - A boolean indicating whether to enable or disable the region.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

void mpu_enable_region(unsigned int region, uint32_t enable);

/****************************************************************************
 * Name: mpu_configure_region
 *
 * Description:
 *   Configure a region for privileged, strongly ordered memory
 *
 * Input Parameters:
 *   base - Base address of the region.
 *   size - Size of the region.
 *   flags - Flags to configure the region.
 *
 * Returned Value:
 *   The region number allocated for the configured region.
 *
 ****************************************************************************/

unsigned int mpu_configure_region(uintptr_t base, size_t size,
                                  uint32_t flags);

/****************************************************************************
 * Name: mpu_initialize
 *
 * Description:
 *   Configure a region for privileged, strongly ordered memory
 *
 * Input Parameters:
 *   table      - MPU initialization table.
 *   count      - Initialize the number of entries in the region table.
 *   hfnmiena   - A boolean indicating whether the MPU should enable the
 *                HFNMIENA bit.
 *   privdefena - A boolean indicating whether the MPU should enable the
 *                PRIVDEFENA bit.
 *
 * Returned Value:
 *   NULL.
 *
 ****************************************************************************/

void mpu_initialize(const struct mpu_region_s *table, size_t count,
                    bool hfnmiena, bool privdefena);

/****************************************************************************
 * Inline Functions
 ****************************************************************************/

/****************************************************************************
 * Name: mpu_showtype
 *
 * Description:
 *   Show the characteristics of the MPU
 *
 ****************************************************************************/

#ifdef CONFIG_DEBUG_SCHED_INFO
#  define mpu_showtype() \
    do \
      { \
        uint32_t regval = getreg32(MPU_TYPE); \
        sinfo("%s MPU Regions: data=%d instr=%d\n", \
              (regval & MPU_TYPE_SEPARATE) != 0 ? "Separate" : "Unified", \
              (regval & MPU_TYPE_DREGION_MASK) >> MPU_TYPE_DREGION_SHIFT, \
              (regval & MPU_TYPE_IREGION_MASK) >> MPU_TYPE_IREGION_SHIFT); \
      } \
    while (0)
#else
#  define mpu_showtype()
#endif

/****************************************************************************
 * Name: mpu_priv_stronglyordered
 *
 * Description:
 *   Configure a region for privileged, strongly ordered memory
 *
 ****************************************************************************/

#define mpu_priv_stronglyordered(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO  | /* Ordered            */ \
                                          /* Not Cacheable      */ \
                                          /* Not Bufferable     */ \
                       MPU_RASR_S       | /* Shareable          */ \
                       MPU_RASR_AP_RWNO   /* P:RW   U:None      */ \
                                          /* Instruction access */)

/****************************************************************************
 * Name: mpu_user_flash
 *
 * Description:
 *   Configure a region for user program flash
 *
 ****************************************************************************/

#define mpu_user_flash(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO  | /* Ordered            */ \
                       MPU_RASR_C       | /* Cacheable          */ \
                                          /* Not Bufferable     */ \
                                          /* Not Shareable      */ \
                       MPU_RASR_AP_RORO   /* P:RO   U:RO        */ \
                                          /* Instruction access */)

/****************************************************************************
 * Name: mpu_priv_flash
 *
 * Description:
 *   Configure a region for privileged program flash
 *
 ****************************************************************************/

#define mpu_priv_flash(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO   | /* Ordered            */ \
                       MPU_RASR_C        | /* Cacheable          */ \
                                           /* Not Bufferable     */ \
                                           /* Not Shareable      */ \
                       MPU_RASR_AP_RONO    /* P:RO   U:None      */ \
                                           /* Instruction access */)

/****************************************************************************
 * Name: mpu_user_intsram
 *
 * Description:
 *   Configure a region as user internal SRAM
 *
 ****************************************************************************/

#define mpu_user_intsram(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO   | /* Ordered            */ \
                       MPU_RASR_C        | /* Cacheable          */ \
                                           /* Not Bufferable     */ \
                       MPU_RASR_S        | /* Shareable          */ \
                       MPU_RASR_AP_RWRW    /* P:RW   U:RW        */ \
                                           /* Instruction access */)

/****************************************************************************
 * Name: mpu_priv_intsram
 *
 * Description:
 *   Configure a region as privileged internal SRAM
 *
 ****************************************************************************/

#define mpu_priv_intsram(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO  | /* Ordered            */ \
                       MPU_RASR_C       | /* Cacheable          */ \
                                          /* Not Bufferable     */ \
                       MPU_RASR_S       | /* Shareable          */ \
                       MPU_RASR_AP_RWNO   /* P:RW   U:None      */ \
                                          /* Instruction access */)

/****************************************************************************
 * Name: mpu_priv_shmem
 *
 * Description:
 *   Configure a region as privileged shared memory
 *
 ****************************************************************************/

#define mpu_priv_shmem(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO   | /* Ordered            */ \
                                           /* Not Cacheable      */ \
                       MPU_RASR_B        | /* Bufferable         */ \
                       MPU_RASR_S        | /* Shareable          */ \
                       MPU_RASR_AP_RWNO  | /* P:RW   U:None      */ \
                       MPU_RASR_XN         /* No Instruction access */)

/****************************************************************************
 * Name: mpu_user_extsram
 *
 * Description:
 *   Configure a region as user external SRAM
 *
 ****************************************************************************/

#define mpu_user_extsram(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO   | /* Ordered            */ \
                       MPU_RASR_C        | /* Cacheable          */ \
                       MPU_RASR_B        | /* Bufferable         */ \
                       MPU_RASR_S        | /* Shareable          */ \
                       MPU_RASR_AP_RWRW    /* P:RW   U:RW        */ \
                                           /* Instruction access */)

/****************************************************************************
 * Name: mpu_priv_extsram
 *
 * Description:
 *   Configure a region as privileged external SRAM
 *
 ****************************************************************************/

#define mpu_priv_extsram(base, size) \
  /* The configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_SO   | /* Ordered            */ \
                       MPU_RASR_C        | /* Cacheable          */ \
                       MPU_RASR_B        | /* Bufferable         */ \
                       MPU_RASR_S        | /* Shareable          */ \
                       MPU_RASR_AP_RWNO    /* P:RW   U:None      */ \
                                           /* Instruction access */)

/****************************************************************************
 * Name: mpu_peripheral
 *
 * Description:
 *   Configure a region as privileged peripheral address space
 *
 ****************************************************************************/

#define mpu_peripheral(base, size) \
  /* Then configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_DEV  | /* Device                */ \
                                           /* Not Cacheable         */ \
                       MPU_RASR_B        | /* Bufferable            */ \
                       MPU_RASR_S        | /* Shareable             */ \
                       MPU_RASR_AP_RWNO  | /* P:RW   U:None         */ \
                       MPU_RASR_XN         /* No Instruction access */)

/****************************************************************************
 * Name: mpu_user_peripheral
 *
 * Description:
 *   Configure a region as user peripheral address space
 *
 ****************************************************************************/

#define mpu_user_peripheral(base, size) \
  /* Then configure the region */ \
  mpu_configure_region(base, size, \
                       MPU_RASR_TEX_DEV  | /* Device                */ \
                                           /* Not Cacheable         */ \
                       MPU_RASR_B        | /* Bufferable            */ \
                       MPU_RASR_S        | /* Shareable             */ \
                       MPU_RASR_AP_RWRW  | /* P:RW     U:RW         */ \
                       MPU_RASR_XN         /* No Instruction access */)

#undef EXTERN
#if defined(__cplusplus)
}
#endif

#endif /* __ASSEMBLY__ */
#endif /* CONFIG_ARM_MPU */
#endif /* __ARCH_ARM_SRC_ARMV7_M_MPU_H */