LCOV - code coverage report
Current view: top level - arch/arm/core/aarch32/mpu - arm_mpu_v8_internal.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 52 137 38.0 %
Date: 2022-08-18 11:36:24 Functions: 9 16 56.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 10 54 18.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2017 Linaro Limited.
       3                 :            :  * Copyright (c) 2018 Nordic Semiconductor ASA.
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: Apache-2.0
       6                 :            :  */
       7                 :            : 
       8                 :            : #ifndef ZEPHYR_ARCH_ARM_CORE_AARCH32_MPU_ARM_MPU_V8_INTERNAL_H_
       9                 :            : #define ZEPHYR_ARCH_ARM_CORE_AARCH32_MPU_ARM_MPU_V8_INTERNAL_H_
      10                 :            : 
      11                 :            : #include <aarch32/cortex_m/cmse.h>
      12                 :            : #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
      13                 :            : #include <logging/log.h>
      14                 :            : 
      15                 :            : /**
      16                 :            :  * @brief internal structure holding information of
      17                 :            :  *        memory areas where dynamic MPU programming
      18                 :            :  *        is allowed.
      19                 :            :  */
      20                 :            : struct dynamic_region_info {
      21                 :            :         int index;
      22                 :            :         struct arm_mpu_region region_conf;
      23                 :            : };
      24                 :            : 
      25                 :            : /**
      26                 :            :  * Global array, holding the MPU region index of
      27                 :            :  * the memory region inside which dynamic memory
      28                 :            :  * regions may be configured.
      29                 :            :  */
      30                 :            : static struct dynamic_region_info dyn_reg_info[MPU_DYNAMIC_REGION_AREAS_NUM];
      31                 :            : 
      32                 :            : 
      33                 :            : /* Global MPU configuration at system initialization. */
      34                 :          1 : static void mpu_init(void)
      35                 :            : {
      36                 :            :         /* Configure the cache-ability attributes for all the
      37                 :            :          * different types of memory regions.
      38                 :            :          */
      39                 :            : 
      40                 :            :         /* Flash region(s): Attribute-0
      41                 :            :          * SRAM region(s): Attribute-1
      42                 :            :          * SRAM no cache-able regions(s): Attribute-2
      43                 :            :          */
      44                 :          1 :         MPU->MAIR0 =
      45                 :            :                 ((MPU_MAIR_ATTR_FLASH << MPU_MAIR0_Attr0_Pos) &
      46                 :            :                         MPU_MAIR0_Attr0_Msk)
      47                 :            :                 |
      48                 :            :                 ((MPU_MAIR_ATTR_SRAM << MPU_MAIR0_Attr1_Pos) &
      49                 :            :                         MPU_MAIR0_Attr1_Msk)
      50                 :            :                 |
      51                 :            :                 ((MPU_MAIR_ATTR_SRAM_NOCACHE << MPU_MAIR0_Attr2_Pos) &
      52                 :            :                         MPU_MAIR0_Attr2_Msk);
      53                 :          1 : }
      54                 :            : 
      55                 :            : /* This internal function performs MPU region initialization.
      56                 :            :  *
      57                 :            :  * Note:
      58                 :            :  *   The caller must provide a valid region index.
      59                 :            :  */
      60                 :          2 : static void region_init(const uint32_t index,
      61                 :            :         const struct arm_mpu_region *region_conf)
      62                 :            : {
      63                 :          2 :         ARM_MPU_SetRegion(
      64                 :            :                 /* RNR */
      65                 :            :                 index,
      66                 :            :                 /* RBAR */
      67                 :          2 :                 (region_conf->base & MPU_RBAR_BASE_Msk)
      68                 :          2 :                 | (region_conf->attr.rbar &
      69                 :            :                         (MPU_RBAR_XN_Msk | MPU_RBAR_AP_Msk | MPU_RBAR_SH_Msk)),
      70                 :            :                 /* RLAR */
      71                 :          2 :                 (region_conf->attr.r_limit & MPU_RLAR_LIMIT_Msk)
      72                 :          2 :                 | ((region_conf->attr.mair_idx << MPU_RLAR_AttrIndx_Pos)
      73                 :          2 :                         & MPU_RLAR_AttrIndx_Msk)
      74                 :          2 :                 | MPU_RLAR_EN_Msk
      75                 :            :         );
      76                 :            : 
      77         [ +  - ]:          2 :         LOG_DBG("[%d] 0x%08x 0x%08x 0x%08x 0x%08x",
      78                 :            :                         index, region_conf->base, region_conf->attr.rbar,
      79                 :            :                         region_conf->attr.mair_idx, region_conf->attr.r_limit);
      80                 :          2 : }
      81                 :            : 
      82                 :            : /* @brief Partition sanity check
      83                 :            :  *
      84                 :            :  * This internal function performs run-time sanity check for
      85                 :            :  * MPU region start address and size.
      86                 :            :  *
      87                 :            :  * @param part Pointer to the data structure holding the partition
      88                 :            :  *             information (must be valid).
      89                 :            :  * */
      90                 :          0 : static int mpu_partition_is_valid(const struct z_arm_mpu_partition *part)
      91                 :            : {
      92                 :            :         /* Partition size must be a multiple of the minimum MPU region
      93                 :            :          * size. Start address of the partition must align with the
      94                 :            :          * minimum MPU region size.
      95                 :            :          */
      96                 :          0 :         int partition_is_valid =
      97                 :          0 :                 (part->size >= CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE)
      98                 :          0 :                 &&
      99                 :          0 :                 ((part->size &
     100                 :            :                         (~(CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE - 1)))
     101         [ #  # ]:          0 :                         == part->size)
     102         [ #  # ]:          0 :                 &&
     103         [ #  # ]:          0 :                 ((part->start &
     104                 :            :                         (CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE - 1)) == 0U);
     105                 :            : 
     106                 :          0 :         return partition_is_valid;
     107                 :            : }
     108                 :            : 
     109                 :            : /**
     110                 :            :  * This internal function returns the MPU region, in which a
     111                 :            :  * buffer, specified by its start address and size, lies. If
     112                 :            :  * a valid MPU region cannot be derived the function returns
     113                 :            :  * -EINVAL.
     114                 :            :  *
     115                 :            :  * Note that, for the function to work properly, the ARM MPU
     116                 :            :  * needs to be enabled.
     117                 :            :  *
     118                 :            :  */
     119                 :          1 : static inline int get_region_index(uint32_t start, uint32_t size)
     120                 :            : {
     121                 :          1 :         uint32_t region_start_addr = arm_cmse_mpu_region_get(start);
     122                 :          1 :         uint32_t region_end_addr = arm_cmse_mpu_region_get(start + size - 1);
     123                 :            : 
     124                 :            :         /* MPU regions are contiguous so return the region number,
     125                 :            :          * if both start and end address are in the same region.
     126                 :            :          */
     127         [ +  - ]:          1 :         if (region_start_addr == region_end_addr) {
     128                 :          1 :                 return region_start_addr;
     129                 :            :         }
     130                 :          0 :         return -EINVAL;
     131                 :            : }
     132                 :            : 
     133                 :          0 : static inline uint32_t mpu_region_get_base(const uint32_t index)
     134                 :            : {
     135                 :          0 :         MPU->RNR = index;
     136                 :          0 :         return MPU->RBAR & MPU_RBAR_BASE_Msk;
     137                 :            : }
     138                 :            : 
     139                 :          0 : static inline void mpu_region_set_base(const uint32_t index, const uint32_t base)
     140                 :            : {
     141                 :          0 :         MPU->RNR = index;
     142                 :          0 :         MPU->RBAR = (MPU->RBAR & (~MPU_RBAR_BASE_Msk))
     143                 :          0 :                 | (base & MPU_RBAR_BASE_Msk);
     144                 :          0 : }
     145                 :            : 
     146                 :          0 : static inline uint32_t mpu_region_get_last_addr(const uint32_t index)
     147                 :            : {
     148                 :          0 :         MPU->RNR = index;
     149                 :          0 :         return (MPU->RLAR & MPU_RLAR_LIMIT_Msk) | (~MPU_RLAR_LIMIT_Msk);
     150                 :            : }
     151                 :            : 
     152                 :          0 : static inline void mpu_region_set_limit(const uint32_t index, const uint32_t limit)
     153                 :            : {
     154                 :          0 :         MPU->RNR = index;
     155                 :          0 :         MPU->RLAR = (MPU->RLAR & (~MPU_RLAR_LIMIT_Msk))
     156                 :          0 :                 | (limit & MPU_RLAR_LIMIT_Msk);
     157                 :          0 : }
     158                 :            : 
     159                 :          1 : static inline void mpu_region_get_access_attr(const uint32_t index,
     160                 :            :         arm_mpu_region_attr_t *attr)
     161                 :            : {
     162                 :          1 :         MPU->RNR = index;
     163                 :            : 
     164                 :          1 :         attr->rbar = MPU->RBAR &
     165                 :            :                 (MPU_RBAR_XN_Msk | MPU_RBAR_AP_Msk | MPU_RBAR_SH_Msk);
     166                 :          1 :         attr->mair_idx = (MPU->RLAR & MPU_RLAR_AttrIndx_Msk) >>
     167                 :            :                 MPU_RLAR_AttrIndx_Pos;
     168                 :          1 : }
     169                 :            : 
     170                 :          1 : static inline void mpu_region_get_conf(const uint32_t index,
     171                 :            :         struct arm_mpu_region *region_conf)
     172                 :            : {
     173                 :          1 :         MPU->RNR = index;
     174                 :            : 
     175                 :            :         /* Region attribution:
     176                 :            :          * - Cache-ability
     177                 :            :          * - Share-ability
     178                 :            :          * - Access Permissions
     179                 :            :          */
     180                 :          1 :         mpu_region_get_access_attr(index, &region_conf->attr);
     181                 :            : 
     182                 :            :         /* Region base address */
     183                 :          1 :         region_conf->base = (MPU->RBAR & MPU_RBAR_BASE_Msk);
     184                 :            : 
     185                 :            :         /* Region limit address */
     186                 :          1 :         region_conf->attr.r_limit = MPU->RLAR & MPU_RLAR_LIMIT_Msk;
     187                 :          1 : }
     188                 :            : 
     189                 :            : /**
     190                 :            :  * This internal function is utilized by the MPU driver to combine a given
     191                 :            :  * region attribute configuration and size and fill-in a driver-specific
     192                 :            :  * structure with the correct MPU region configuration.
     193                 :            :  */
     194                 :          0 : static inline void get_region_attr_from_mpu_partition_info(
     195                 :            :         arm_mpu_region_attr_t *p_attr,
     196                 :            :         const k_mem_partition_attr_t *attr, uint32_t base, uint32_t size)
     197                 :            : {
     198                 :          0 :         p_attr->rbar = attr->rbar &
     199                 :            :                 (MPU_RBAR_XN_Msk | MPU_RBAR_AP_Msk | MPU_RBAR_SH_Msk);
     200                 :          0 :         p_attr->mair_idx = attr->mair_idx;
     201                 :          0 :         p_attr->r_limit = REGION_LIMIT_ADDR(base, size);
     202                 :          0 : }
     203                 :            : 
     204                 :            : #if defined(CONFIG_USERSPACE)
     205                 :            : 
     206                 :            : /**
     207                 :            :  * This internal function returns the minimum HW MPU region index
     208                 :            :  * that may hold the configuration of a dynamic memory region.
     209                 :            :  *
     210                 :            :  * Browse through the memory areas marked for dynamic MPU programming,
     211                 :            :  * pick the one with the minimum MPU region index. Return that index.
     212                 :            :  *
     213                 :            :  * The function is optimized for the (most common) use-case of a single
     214                 :            :  * marked area for dynamic memory regions.
     215                 :            :  */
     216                 :            : static inline int get_dyn_region_min_index(void)
     217                 :            : {
     218                 :            :         int dyn_reg_min_index = dyn_reg_info[0].index;
     219                 :            : #if MPU_DYNAMIC_REGION_AREAS_NUM > 1
     220                 :            :         for (int i = 1; i < MPU_DYNAMIC_REGION_AREAS_NUM; i++) {
     221                 :            :                 if ((dyn_reg_info[i].index != -EINVAL) &&
     222                 :            :                         (dyn_reg_info[i].index < dyn_reg_min_index)
     223                 :            :                 ) {
     224                 :            :                         dyn_reg_min_index = dyn_reg_info[i].index;
     225                 :            :                 }
     226                 :            :         }
     227                 :            : #endif
     228                 :            :         return dyn_reg_min_index;
     229                 :            : }
     230                 :            : 
     231                 :            : static inline uint32_t mpu_region_get_size(uint32_t index)
     232                 :            : {
     233                 :            :         return mpu_region_get_last_addr(index) + 1
     234                 :            :                 - mpu_region_get_base(index);
     235                 :            : }
     236                 :            : 
     237                 :            : /**
     238                 :            :  * This internal function checks if region is enabled or not.
     239                 :            :  *
     240                 :            :  * Note:
     241                 :            :  *   The caller must provide a valid region number.
     242                 :            :  */
     243                 :            : static inline int is_enabled_region(uint32_t index)
     244                 :            : {
     245                 :            :         MPU->RNR = index;
     246                 :            : 
     247                 :            :         return (MPU->RLAR & MPU_RLAR_EN_Msk) ? 1 : 0;
     248                 :            : }
     249                 :            : 
     250                 :            : /**
     251                 :            :  * This internal function validates whether a given memory buffer
     252                 :            :  * is user accessible or not.
     253                 :            :  *
     254                 :            :  * Note: [Doc. number: ARM-ECM-0359818]
     255                 :            :  * "Some SAU, IDAU, and MPU configurations block the efficient implementation
     256                 :            :  * of an address range check. The CMSE intrinsic operates under the assumption
     257                 :            :  * that the configuration of the SAU, IDAU, and MPU is constrained as follows:
     258                 :            :  * - An object is allocated in a single MPU/SAU/IDAU region.
     259                 :            :  * - A stack is allocated in a single region.
     260                 :            :  *
     261                 :            :  * These points imply that the memory buffer does not span across multiple MPU,
     262                 :            :  * SAU, or IDAU regions."
     263                 :            :  *
     264                 :            :  * MPU regions are configurable, however, some platforms might have fixed-size
     265                 :            :  * SAU or IDAU regions. So, even if a buffer is allocated inside a single MPU
     266                 :            :  * region, it might span across multiple SAU/IDAU regions, which will make the
     267                 :            :  * TT-based address range check fail.
     268                 :            :  *
     269                 :            :  * Therefore, the function performs a second check, which is based on MPU only,
     270                 :            :  * in case the fast address range check fails.
     271                 :            :  *
     272                 :            :  */
     273                 :            : static inline int mpu_buffer_validate(void *addr, size_t size, int write)
     274                 :            : {
     275                 :            :         uint32_t _addr = (uint32_t)addr;
     276                 :            :         uint32_t _size = (uint32_t)size;
     277                 :            : 
     278                 :            :         if (write) {
     279                 :            :                 if (arm_cmse_addr_range_readwrite_ok(_addr, _size, 1)) {
     280                 :            :                         return 0;
     281                 :            :                 }
     282                 :            :         } else {
     283                 :            :                 if (arm_cmse_addr_range_read_ok(_addr, _size, 1)) {
     284                 :            :                         return 0;
     285                 :            :                 }
     286                 :            :         }
     287                 :            : 
     288                 :            : #if defined(CONFIG_CPU_HAS_TEE)
     289                 :            :         /*
     290                 :            :          * Validation failure may be due to SAU/IDAU presence.
     291                 :            :          * We re-check user accessibility based on MPU only.
     292                 :            :          */
     293                 :            :         int32_t r_index_base = arm_cmse_mpu_region_get(_addr);
     294                 :            :         int32_t r_index_last = arm_cmse_mpu_region_get(_addr + _size - 1);
     295                 :            : 
     296                 :            :         if ((r_index_base != -EINVAL) && (r_index_base == r_index_last)) {
     297                 :            :                 /* Valid MPU region, check permissions on base address only. */
     298                 :            :                 if (write) {
     299                 :            :                         if (arm_cmse_addr_readwrite_ok(_addr, 1)) {
     300                 :            :                                 return 0;
     301                 :            :                         }
     302                 :            :                 } else {
     303                 :            :                         if (arm_cmse_addr_read_ok(_addr, 1)) {
     304                 :            :                                 return 0;
     305                 :            :                         }
     306                 :            :                 }
     307                 :            :         }
     308                 :            : #endif /* CONFIG_CPU_HAS_TEE */
     309                 :            :         return -EPERM;
     310                 :            : }
     311                 :            : 
     312                 :            : 
     313                 :            : #endif /* CONFIG_USERSPACE */
     314                 :            : 
     315                 :            : static int region_allocate_and_init(const uint8_t index,
     316                 :            :         const struct arm_mpu_region *region_conf);
     317                 :            : 
     318                 :            : static int mpu_configure_region(const uint8_t index,
     319                 :            :         const struct z_arm_mpu_partition *new_region);
     320                 :            : 
     321                 :            : #if !defined(CONFIG_MPU_GAP_FILLING)
     322                 :            : static int mpu_configure_regions(const struct z_arm_mpu_partition
     323                 :            :         regions[], uint8_t regions_num, uint8_t start_reg_index,
     324                 :            :         bool do_sanity_check);
     325                 :            : #endif
     326                 :            : 
     327                 :            : /* This internal function programs a set of given MPU regions
     328                 :            :  * over a background memory area, optionally performing a
     329                 :            :  * sanity check of the memory regions to be programmed.
     330                 :            :  *
     331                 :            :  * The function performs a full partition of the background memory
     332                 :            :  * area, effectively, leaving no space in this area uncovered by MPU.
     333                 :            :  */
     334                 :          1 : static int mpu_configure_regions_and_partition(const struct z_arm_mpu_partition
     335                 :            :         regions[], uint8_t regions_num, uint8_t start_reg_index,
     336                 :            :         bool do_sanity_check)
     337                 :            : {
     338                 :            :         int i;
     339                 :          1 :         int reg_index = start_reg_index;
     340                 :            : 
     341         [ +  + ]:          2 :         for (i = 0; i < regions_num; i++) {
     342         [ +  - ]:          1 :                 if (regions[i].size == 0U) {
     343                 :          1 :                         continue;
     344                 :            :                 }
     345                 :            :                 /* Non-empty region. */
     346                 :            : 
     347   [ #  #  #  # ]:          0 :                 if (do_sanity_check &&
     348                 :          0 :                         (!mpu_partition_is_valid(&regions[i]))) {
     349         [ #  # ]:          0 :                         LOG_ERR("Partition %u: sanity check failed.", i);
     350                 :          0 :                         return -EINVAL;
     351                 :            :                 }
     352                 :            : 
     353                 :            :                 /* Derive the index of the underlying MPU region,
     354                 :            :                  * inside which the new region will be configured.
     355                 :            :                  */
     356                 :            :                 int u_reg_index =
     357                 :          0 :                         get_region_index(regions[i].start, regions[i].size);
     358                 :            : 
     359   [ #  #  #  # ]:          0 :                 if ((u_reg_index == -EINVAL) ||
     360                 :            :                         (u_reg_index > (reg_index - 1))) {
     361         [ #  # ]:          0 :                         LOG_ERR("Invalid underlying region index %u",
     362                 :            :                                 u_reg_index);
     363                 :          0 :                         return -EINVAL;
     364                 :            :                 }
     365                 :            : 
     366                 :            :                 /*
     367                 :            :                  * The new memory region is to be placed inside the underlying
     368                 :            :                  * region, possibly splitting the underlying region into two.
     369                 :            :                  */
     370                 :          0 :                 uint32_t u_reg_base = mpu_region_get_base(u_reg_index);
     371                 :          0 :                 uint32_t u_reg_last = mpu_region_get_last_addr(u_reg_index);
     372                 :          0 :                 uint32_t reg_last = regions[i].start + regions[i].size - 1;
     373                 :            : 
     374   [ #  #  #  # ]:          0 :                 if ((regions[i].start == u_reg_base) &&
     375                 :            :                         (reg_last == u_reg_last)) {
     376                 :            :                         /* The new region overlaps entirely with the
     377                 :            :                          * underlying region. In this case we simply
     378                 :            :                          * update the partition attributes of the
     379                 :            :                          * underlying region with those of the new
     380                 :            :                          * region.
     381                 :            :                          */
     382                 :          0 :                         mpu_configure_region(u_reg_index, &regions[i]);
     383         [ #  # ]:          0 :                 } else if (regions[i].start == u_reg_base) {
     384                 :            :                         /* The new region starts exactly at the start of the
     385                 :            :                          * underlying region; the start of the underlying
     386                 :            :                          * region needs to be set to the end of the new region.
     387                 :            :                          */
     388                 :          0 :                         mpu_region_set_base(u_reg_index,
     389                 :          0 :                                 regions[i].start + regions[i].size);
     390                 :            : 
     391                 :            :                         reg_index =
     392                 :          0 :                                 mpu_configure_region(reg_index, &regions[i]);
     393                 :            : 
     394         [ #  # ]:          0 :                         if (reg_index == -EINVAL) {
     395                 :          0 :                                 return reg_index;
     396                 :            :                         }
     397                 :            : 
     398                 :          0 :                         reg_index++;
     399         [ #  # ]:          0 :                 } else if (reg_last == u_reg_last) {
     400                 :            :                         /* The new region ends exactly at the end of the
     401                 :            :                          * underlying region; the end of the underlying
     402                 :            :                          * region needs to be set to the start of the
     403                 :            :                          * new region.
     404                 :            :                          */
     405                 :          0 :                         mpu_region_set_limit(u_reg_index,
     406                 :          0 :                                 regions[i].start - 1);
     407                 :            : 
     408                 :            :                         reg_index =
     409                 :          0 :                                 mpu_configure_region(reg_index, &regions[i]);
     410                 :            : 
     411         [ #  # ]:          0 :                         if (reg_index == -EINVAL) {
     412                 :          0 :                                 return reg_index;
     413                 :            :                         }
     414                 :            : 
     415                 :          0 :                         reg_index++;
     416                 :            :                 } else {
     417                 :            :                         /* The new regions lies strictly inside the
     418                 :            :                          * underlying region, which needs to split
     419                 :            :                          * into two regions.
     420                 :            :                          */
     421                 :          0 :                         mpu_region_set_limit(u_reg_index,
     422                 :          0 :                                 regions[i].start - 1);
     423                 :            : 
     424                 :            :                         reg_index =
     425                 :          0 :                                 mpu_configure_region(reg_index, &regions[i]);
     426                 :            : 
     427         [ #  # ]:          0 :                         if (reg_index == -EINVAL) {
     428                 :          0 :                                 return reg_index;
     429                 :            :                         }
     430                 :          0 :                         reg_index++;
     431                 :            : 
     432                 :            :                         /* The additional region shall have the same
     433                 :            :                          * access attributes as the initial underlying
     434                 :            :                          * region.
     435                 :            :                          */
     436                 :            :                         struct arm_mpu_region fill_region;
     437                 :            : 
     438                 :          0 :                         mpu_region_get_access_attr(u_reg_index,
     439                 :            :                                 &fill_region.attr);
     440                 :          0 :                         fill_region.base = regions[i].start +
     441                 :          0 :                                 regions[i].size;
     442                 :          0 :                         fill_region.attr.r_limit =
     443                 :          0 :                         REGION_LIMIT_ADDR((regions[i].start +
     444                 :            :                                 regions[i].size), (u_reg_last - reg_last));
     445                 :            : 
     446                 :            :                         reg_index =
     447                 :          0 :                                 region_allocate_and_init(reg_index,
     448                 :            :                                         (const struct arm_mpu_region *)
     449                 :            :                                                 &fill_region);
     450                 :            : 
     451         [ #  # ]:          0 :                         if (reg_index == -EINVAL) {
     452                 :          0 :                                 return reg_index;
     453                 :            :                         }
     454                 :            : 
     455                 :          0 :                         reg_index++;
     456                 :            :                 }
     457                 :            :         }
     458                 :            : 
     459                 :          1 :         return reg_index;
     460                 :            : }
     461                 :            : 
     462                 :            : /* This internal function programs the static MPU regions.
     463                 :            :  *
     464                 :            :  * It returns the number of MPU region indices configured.
     465                 :            :  *
     466                 :            :  * Note:
     467                 :            :  * If the static MPU regions configuration has not been successfully
     468                 :            :  * performed, the error signal is propagated to the caller of the function.
     469                 :            :  */
     470                 :          1 : static int mpu_configure_static_mpu_regions(const struct z_arm_mpu_partition
     471                 :            :         static_regions[], const uint8_t regions_num,
     472                 :            :         const uint32_t background_area_base,
     473                 :            :         const uint32_t background_area_end)
     474                 :            : {
     475                 :          1 :         int mpu_reg_index = static_regions_num;
     476                 :            : 
     477                 :            :         /* In ARMv8-M architecture the static regions are programmed on SRAM,
     478                 :            :          * forming a full partition of the background area, specified by the
     479                 :            :          * given boundaries.
     480                 :            :          */
     481                 :            :         ARG_UNUSED(background_area_base);
     482                 :            :         ARG_UNUSED(background_area_end);
     483                 :            : 
     484                 :          1 :         mpu_reg_index = mpu_configure_regions_and_partition(static_regions,
     485                 :            :                 regions_num, mpu_reg_index, true);
     486                 :            : 
     487                 :          1 :         static_regions_num = mpu_reg_index;
     488                 :            : 
     489                 :          1 :         return mpu_reg_index;
     490                 :            : }
     491                 :            : 
     492                 :            : /* This internal function marks and stores the configuration of memory areas
     493                 :            :  * where dynamic region programming is allowed. Return zero on success, or
     494                 :            :  * -EINVAL on error.
     495                 :            :  */
     496                 :          1 : static int mpu_mark_areas_for_dynamic_regions(
     497                 :            :                 const struct z_arm_mpu_partition dyn_region_areas[],
     498                 :            :                 const uint8_t dyn_region_areas_num)
     499                 :            : {
     500                 :            :         /* In ARMv8-M architecture we need to store the index values
     501                 :            :          * and the default configuration of the MPU regions, inside
     502                 :            :          * which dynamic memory regions may be programmed at run-time.
     503                 :            :          */
     504         [ +  + ]:          2 :         for (int i = 0; i < dyn_region_areas_num; i++) {
     505         [ -  + ]:          1 :                 if (dyn_region_areas[i].size == 0U) {
     506                 :          0 :                         continue;
     507                 :            :                 }
     508                 :            :                 /* Non-empty area */
     509                 :            : 
     510                 :            :                 /* Retrieve HW MPU region index */
     511                 :          1 :                 dyn_reg_info[i].index =
     512                 :          1 :                         get_region_index(dyn_region_areas[i].start,
     513                 :          1 :                                         dyn_region_areas[i].size);
     514                 :            : 
     515         [ -  + ]:          1 :                 if (dyn_reg_info[i].index == -EINVAL) {
     516                 :            : 
     517                 :          0 :                         return -EINVAL;
     518                 :            :                 }
     519                 :            : 
     520         [ -  + ]:          1 :                 if (dyn_reg_info[i].index >= static_regions_num) {
     521                 :            : 
     522                 :          0 :                         return -EINVAL;
     523                 :            :                 }
     524                 :            : 
     525                 :            :                 /* Store default configuration */
     526                 :          1 :                 mpu_region_get_conf(dyn_reg_info[i].index,
     527                 :            :                         &dyn_reg_info[i].region_conf);
     528                 :            :         }
     529                 :            : 
     530                 :          1 :         return 0;
     531                 :            : }
     532                 :            : 
     533                 :            : /**
     534                 :            :  *  Get the number of supported MPU regions.
     535                 :            :  */
     536                 :          1 : static inline uint8_t get_num_regions(void)
     537                 :            : {
     538                 :            : #if defined(NUM_MPU_REGIONS)
     539                 :            :         /* Retrieve the number of regions from DTS configuration. */
     540                 :          1 :         return NUM_MPU_REGIONS;
     541                 :            : #else
     542                 :            :         uint32_t type = MPU->TYPE;
     543                 :            : 
     544                 :            :         type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
     545                 :            : 
     546                 :            :         return (uint8_t)type;
     547                 :            : #endif /* NUM_MPU_REGIONS */
     548                 :            : }
     549                 :            : 
     550                 :            : /* This internal function programs the dynamic MPU regions.
     551                 :            :  *
     552                 :            :  * It returns the number of MPU region indices configured.
     553                 :            :  *
     554                 :            :  * Note:
     555                 :            :  * If the dynamic MPU regions configuration has not been successfully
     556                 :            :  * performed, the error signal is propagated to the caller of the function.
     557                 :            :  */
     558                 :          0 : static int mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition
     559                 :            :         dynamic_regions[], uint8_t regions_num)
     560                 :            : {
     561                 :          0 :         int mpu_reg_index = static_regions_num;
     562                 :            : 
     563                 :            :         /* Disable all MPU regions except for the static ones. */
     564         [ #  # ]:          0 :         for (int i = mpu_reg_index; i < get_num_regions(); i++) {
     565                 :          0 :                 ARM_MPU_ClrRegion(i);
     566                 :            :         }
     567                 :            : 
     568                 :            : #if defined(CONFIG_MPU_GAP_FILLING)
     569                 :            :         /* Reset MPU regions inside which dynamic memory regions may
     570                 :            :          * be programmed.
     571                 :            :          */
     572         [ #  # ]:          0 :         for (int i = 0; i < MPU_DYNAMIC_REGION_AREAS_NUM; i++) {
     573                 :          0 :                 region_init(dyn_reg_info[i].index,
     574                 :          0 :                         &dyn_reg_info[i].region_conf);
     575                 :            :         }
     576                 :            : 
     577                 :            :         /* In ARMv8-M architecture the dynamic regions are programmed on SRAM,
     578                 :            :          * forming a full partition of the background area, specified by the
     579                 :            :          * given boundaries.
     580                 :            :          */
     581                 :          0 :         mpu_reg_index = mpu_configure_regions_and_partition(dynamic_regions,
     582                 :            :                 regions_num, mpu_reg_index, true);
     583                 :            : #else
     584                 :            : 
     585                 :            :         /* We are going to skip the full partition of the background areas.
     586                 :            :          * So we can disable MPU regions inside which dynamic memory regions
     587                 :            :          * may be programmed.
     588                 :            :          */
     589                 :            :         for (int i = 0; i < MPU_DYNAMIC_REGION_AREAS_NUM; i++) {
     590                 :            :                 ARM_MPU_ClrRegion(dyn_reg_info[i].index);
     591                 :            :         }
     592                 :            : 
     593                 :            :         /* The dynamic regions are now programmed on top of
     594                 :            :          * existing SRAM region configuration.
     595                 :            :          */
     596                 :            :         mpu_reg_index = mpu_configure_regions(dynamic_regions,
     597                 :            :                 regions_num, mpu_reg_index, true);
     598                 :            : 
     599                 :            : #endif /* CONFIG_MPU_GAP_FILLING */
     600                 :          0 :         return mpu_reg_index;
     601                 :            : }
     602                 :            : 
     603                 :            : #endif  /* ZEPHYR_ARCH_ARM_CORE_AARCH32_MPU_ARM_MPU_V8_INTERNAL_H_ */

Generated by: LCOV version 1.14