LCOV - code coverage report
Current view: top level - arch/arm/core/aarch32/mpu - arm_mpu.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 23 44 52.3 %
Date: 2022-08-18 11:36:24 Functions: 5 8 62.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 22 31.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2017 Linaro Limited.
       3                 :            :  *
       4                 :            :  * SPDX-License-Identifier: Apache-2.0
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <device.h>
       8                 :            : #include <init.h>
       9                 :            : #include <kernel.h>
      10                 :            : #include <soc.h>
      11                 :            : #include "arm_core_mpu_dev.h"
      12                 :            : #include <linker/linker-defs.h>
      13                 :            : #include <kernel_arch_data.h>
      14                 :            : 
      15                 :            : #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
      16                 :            : #include <logging/log.h>
      17                 :            : LOG_MODULE_DECLARE(mpu);
      18                 :            : 
      19                 :            : #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
      20                 :            : /* The order here is on purpose since ARMv8-M SoCs may define
      21                 :            :  * CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE
      22                 :            :  * so we want to check for ARMv8-M first.
      23                 :            :  */
      24                 :            : #define MPU_NODEID DT_INST(0, arm_armv8m_mpu)
      25                 :            : #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
      26                 :            : #define MPU_NODEID DT_INST(0, arm_armv7m_mpu)
      27                 :            : #elif defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
      28                 :            : #define MPU_NODEID DT_INST(0, arm_armv6m_mpu)
      29                 :            : #endif
      30                 :            : 
      31                 :            : #if DT_NODE_HAS_PROP(MPU_NODEID, arm_num_mpu_regions)
      32                 :            : #define NUM_MPU_REGIONS   DT_PROP(MPU_NODEID, arm_num_mpu_regions)
      33                 :            : #endif
      34                 :            : 
      35                 :            : /*
      36                 :            :  * Global status variable holding the number of HW MPU region indices, which
      37                 :            :  * have been reserved by the MPU driver to program the static (fixed) memory
      38                 :            :  * regions.
      39                 :            :  */
      40                 :            : static uint8_t static_regions_num;
      41                 :            : 
      42                 :            : /* Include architecture-specific internal headers. */
      43                 :            : #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \
      44                 :            :         defined(CONFIG_CPU_CORTEX_M3) || \
      45                 :            :         defined(CONFIG_CPU_CORTEX_M4) || \
      46                 :            :         defined(CONFIG_CPU_CORTEX_M7) || \
      47                 :            :         defined(CONFIG_CPU_AARCH32_CORTEX_R)
      48                 :            : #include "arm_mpu_v7_internal.h"
      49                 :            : #elif defined(CONFIG_CPU_CORTEX_M23) || \
      50                 :            :         defined(CONFIG_CPU_CORTEX_M33) || \
      51                 :            :         defined(CONFIG_CPU_CORTEX_M55)
      52                 :            : #include "arm_mpu_v8_internal.h"
      53                 :            : #else
      54                 :            : #error "Unsupported ARM CPU"
      55                 :            : #endif
      56                 :            : 
      57                 :          0 : static int region_allocate_and_init(const uint8_t index,
      58                 :            :         const struct arm_mpu_region *region_conf)
      59                 :            : {
      60                 :            :         /* Attempt to allocate new region index. */
      61         [ #  # ]:          0 :         if (index > (get_num_regions() - 1U)) {
      62                 :            : 
      63                 :            :                 /* No available MPU region index. */
      64         [ #  # ]:          0 :                 LOG_ERR("Failed to allocate new MPU region %u\n", index);
      65                 :          0 :                 return -EINVAL;
      66                 :            :         }
      67                 :            : 
      68         [ #  # ]:          0 :         LOG_DBG("Program MPU region at index 0x%x", index);
      69                 :            : 
      70                 :            :         /* Program region */
      71                 :          0 :         region_init(index, region_conf);
      72                 :            : 
      73                 :          0 :         return index;
      74                 :            : }
      75                 :            : 
      76                 :            : /* This internal function programs an MPU region
      77                 :            :  * of a given configuration at a given MPU index.
      78                 :            :  */
      79                 :          0 : static int mpu_configure_region(const uint8_t index,
      80                 :            :         const struct z_arm_mpu_partition *new_region)
      81                 :            : {
      82                 :            :         struct arm_mpu_region region_conf;
      83                 :            : 
      84         [ #  # ]:          0 :         LOG_DBG("Configure MPU region at index 0x%x", index);
      85                 :            : 
      86                 :            :         /* Populate internal ARM MPU region configuration structure. */
      87                 :          0 :         region_conf.base = new_region->start;
      88                 :            : #if defined(CONFIG_CPU_AARCH32_CORTEX_R)
      89                 :            :         region_conf.size = size_to_mpu_rasr_size(new_region->size);
      90                 :            : #endif
      91                 :          0 :         get_region_attr_from_mpu_partition_info(&region_conf.attr,
      92                 :          0 :                 &new_region->attr, new_region->start, new_region->size);
      93                 :            : 
      94                 :            :         /* Allocate and program region */
      95                 :          0 :         return region_allocate_and_init(index,
      96                 :            :                 (const struct arm_mpu_region *)&region_conf);
      97                 :            : }
      98                 :            : 
      99                 :            : #if !defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS) || \
     100                 :            :         !defined(CONFIG_MPU_GAP_FILLING)
     101                 :            : /* This internal function programs a set of given MPU regions
     102                 :            :  * over a background memory area, optionally performing a
     103                 :            :  * sanity check of the memory regions to be programmed.
     104                 :            :  */
     105                 :            : static int mpu_configure_regions(const struct z_arm_mpu_partition
     106                 :            :         regions[], uint8_t regions_num, uint8_t start_reg_index,
     107                 :            :         bool do_sanity_check)
     108                 :            : {
     109                 :            :         int i;
     110                 :            :         int reg_index = start_reg_index;
     111                 :            : 
     112                 :            :         for (i = 0; i < regions_num; i++) {
     113                 :            :                 if (regions[i].size == 0U) {
     114                 :            :                         continue;
     115                 :            :                 }
     116                 :            :                 /* Non-empty region. */
     117                 :            : 
     118                 :            :                 if (do_sanity_check &&
     119                 :            :                                 (!mpu_partition_is_valid(&regions[i]))) {
     120                 :            :                         LOG_ERR("Partition %u: sanity check failed.", i);
     121                 :            :                         return -EINVAL;
     122                 :            :                 }
     123                 :            : 
     124                 :            :                 reg_index = mpu_configure_region(reg_index, &regions[i]);
     125                 :            : 
     126                 :            :                 if (reg_index == -EINVAL) {
     127                 :            :                         return reg_index;
     128                 :            :                 }
     129                 :            : 
     130                 :            :                 /* Increment number of programmed MPU indices. */
     131                 :            :                 reg_index++;
     132                 :            :         }
     133                 :            : 
     134                 :            :         return reg_index;
     135                 :            : }
     136                 :            : #endif
     137                 :            : 
     138                 :            : /* ARM Core MPU Driver API Implementation for ARM MPU */
     139                 :            : 
     140                 :            : 
     141                 :            : #if defined(CONFIG_CPU_AARCH32_CORTEX_R)
     142                 :            : /**
     143                 :            :  * @brief enable the MPU by setting bit in SCTRL register
     144                 :            :  */
     145                 :            : void arm_core_mpu_enable(void)
     146                 :            : {
     147                 :            :         uint32_t val;
     148                 :            : 
     149                 :            :         val = __get_SCTLR();
     150                 :            :         val |= SCTLR_MPU_ENABLE;
     151                 :            :         /* Make sure that all the registers are set before proceeding */
     152                 :            :         __DSB();
     153                 :            :         __set_SCTLR(val);
     154                 :            :         __ISB();
     155                 :            : }
     156                 :            : 
     157                 :            : /**
     158                 :            :  * @brief disable the MPU by clearing bit in SCTRL register
     159                 :            :  */
     160                 :            : void arm_core_mpu_disable(void)
     161                 :            : {
     162                 :            :         uint32_t val;
     163                 :            : 
     164                 :            :         val = __get_SCTLR();
     165                 :            :         val &= ~SCTLR_MPU_ENABLE;
     166                 :            :         /* Force any outstanding transfers to complete before disabling MPU */
     167                 :            :         __DSB();
     168                 :            :         __set_SCTLR(val);
     169                 :            :         __ISB();
     170                 :            : }
     171                 :            : #else
     172                 :            : /**
     173                 :            :  * @brief enable the MPU
     174                 :            :  */
     175                 :          1 : void arm_core_mpu_enable(void)
     176                 :            : {
     177                 :            :         /* Enable MPU and use the default memory map as a
     178                 :            :          * background region for privileged software access.
     179                 :            :          */
     180                 :          1 :         MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk;
     181                 :            : 
     182                 :            :         /* Make sure that all the registers are set before proceeding */
     183                 :            :         __DSB();
     184                 :            :         __ISB();
     185                 :          1 : }
     186                 :            : 
     187                 :            : /**
     188                 :            :  * @brief disable the MPU
     189                 :            :  */
     190                 :          1 : void arm_core_mpu_disable(void)
     191                 :            : {
     192                 :            :         /* Force any outstanding transfers to complete before disabling MPU */
     193                 :            :         __DMB();
     194                 :            : 
     195                 :            :         /* Disable MPU */
     196                 :          1 :         MPU->CTRL = 0;
     197                 :          1 : }
     198                 :            : #endif
     199                 :            : 
     200                 :            : #if defined(CONFIG_USERSPACE)
     201                 :            : /**
     202                 :            :  * @brief update configuration of an active memory partition
     203                 :            :  */
     204                 :            : void arm_core_mpu_mem_partition_config_update(
     205                 :            :         struct z_arm_mpu_partition *partition,
     206                 :            :         k_mem_partition_attr_t *new_attr)
     207                 :            : {
     208                 :            :         /* Find the partition. ASSERT if not found. */
     209                 :            :         uint8_t i;
     210                 :            :         uint8_t reg_index = get_num_regions();
     211                 :            : 
     212                 :            :         for (i = get_dyn_region_min_index(); i < get_num_regions(); i++) {
     213                 :            :                 if (!is_enabled_region(i)) {
     214                 :            :                         continue;
     215                 :            :                 }
     216                 :            : 
     217                 :            :                 uint32_t base = mpu_region_get_base(i);
     218                 :            : 
     219                 :            :                 if (base != partition->start) {
     220                 :            :                         continue;
     221                 :            :                 }
     222                 :            : 
     223                 :            :                 uint32_t size = mpu_region_get_size(i);
     224                 :            : 
     225                 :            :                 if (size != partition->size) {
     226                 :            :                         continue;
     227                 :            :                 }
     228                 :            : 
     229                 :            :                 /* Region found */
     230                 :            :                 reg_index = i;
     231                 :            :                 break;
     232                 :            :         }
     233                 :            :         __ASSERT(reg_index != get_num_regions(),
     234                 :            :                  "Memory domain partition %p size %zu not found\n",
     235                 :            :                  (void *)partition->start, partition->size);
     236                 :            : 
     237                 :            :         /* Modify the permissions */
     238                 :            :         partition->attr = *new_attr;
     239                 :            :         mpu_configure_region(reg_index, partition);
     240                 :            : }
     241                 :            : 
     242                 :            : /**
     243                 :            :  * @brief get the maximum number of available (free) MPU region indices
     244                 :            :  *        for configuring dynamic MPU partitions
     245                 :            :  */
     246                 :            : int arm_core_mpu_get_max_available_dyn_regions(void)
     247                 :            : {
     248                 :            :         return get_num_regions() - static_regions_num;
     249                 :            : }
     250                 :            : 
     251                 :            : /**
     252                 :            :  * @brief validate the given buffer is user accessible or not
     253                 :            :  *
     254                 :            :  * Presumes the background mapping is NOT user accessible.
     255                 :            :  */
     256                 :            : int arm_core_mpu_buffer_validate(void *addr, size_t size, int write)
     257                 :            : {
     258                 :            :         return mpu_buffer_validate(addr, size, write);
     259                 :            : }
     260                 :            : 
     261                 :            : #endif /* CONFIG_USERSPACE */
     262                 :            : 
     263                 :            : /**
     264                 :            :  * @brief configure fixed (static) MPU regions.
     265                 :            :  */
     266                 :          1 : void arm_core_mpu_configure_static_mpu_regions(const struct z_arm_mpu_partition
     267                 :            :         static_regions[], const uint8_t regions_num,
     268                 :            :         const uint32_t background_area_start, const uint32_t background_area_end)
     269                 :            : {
     270         [ -  + ]:          1 :         if (mpu_configure_static_mpu_regions(static_regions, regions_num,
     271                 :            :                                                background_area_start, background_area_end) == -EINVAL) {
     272                 :            : 
     273                 :          0 :                 __ASSERT(0, "Configuring %u static MPU regions failed\n",
     274                 :            :                         regions_num);
     275                 :            :         }
     276                 :          1 : }
     277                 :            : 
     278                 :            : #if defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS)
     279                 :            : /**
     280                 :            :  * @brief mark memory areas for dynamic region configuration
     281                 :            :  */
     282                 :          1 : void arm_core_mpu_mark_areas_for_dynamic_regions(
     283                 :            :         const struct z_arm_mpu_partition dyn_region_areas[],
     284                 :            :         const uint8_t dyn_region_areas_num)
     285                 :            : {
     286         [ -  + ]:          1 :         if (mpu_mark_areas_for_dynamic_regions(dyn_region_areas,
     287                 :            :                                                  dyn_region_areas_num) == -EINVAL) {
     288                 :            : 
     289                 :          0 :                 __ASSERT(0, "Marking %u areas for dynamic regions failed\n",
     290                 :            :                         dyn_region_areas_num);
     291                 :            :         }
     292                 :          1 : }
     293                 :            : #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS */
     294                 :            : 
     295                 :            : /**
     296                 :            :  * @brief configure dynamic MPU regions.
     297                 :            :  */
     298                 :          0 : void arm_core_mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition
     299                 :            :         dynamic_regions[], uint8_t regions_num)
     300                 :            : {
     301         [ #  # ]:          0 :         if (mpu_configure_dynamic_mpu_regions(dynamic_regions, regions_num)
     302                 :            :                 == -EINVAL) {
     303                 :            : 
     304                 :          0 :                 __ASSERT(0, "Configuring %u dynamic MPU regions failed\n",
     305                 :            :                         regions_num);
     306                 :            :         }
     307                 :          0 : }
     308                 :            : 
     309                 :            : /* ARM MPU Driver Initial Setup */
     310                 :            : 
     311                 :            : /*
     312                 :            :  * @brief MPU default configuration
     313                 :            :  *
     314                 :            :  * This function provides the default configuration mechanism for the Memory
     315                 :            :  * Protection Unit (MPU).
     316                 :            :  */
     317                 :          1 : int z_arm_mpu_init(void)
     318                 :            : {
     319                 :            :         uint32_t r_index;
     320                 :            : 
     321         [ -  + ]:          1 :         if (mpu_config.num_regions > get_num_regions()) {
     322                 :            :                 /* Attempt to configure more MPU regions than
     323                 :            :                  * what is supported by hardware. As this operation
     324                 :            :                  * is executed during system (pre-kernel) initialization,
     325                 :            :                  * we want to ensure we can detect an attempt to
     326                 :            :                  * perform invalid configuration.
     327                 :            :                  */
     328                 :          0 :                 __ASSERT(0,
     329                 :            :                         "Request to configure: %u regions (supported: %u)\n",
     330                 :            :                         mpu_config.num_regions,
     331                 :            :                         get_num_regions()
     332                 :            :                 );
     333                 :          0 :                 return -1;
     334                 :            :         }
     335                 :            : 
     336         [ +  - ]:          1 :         LOG_DBG("total region count: %d", get_num_regions());
     337                 :            : 
     338                 :          1 :         arm_core_mpu_disable();
     339                 :            : 
     340                 :            : #if defined(CONFIG_NOCACHE_MEMORY)
     341                 :            :         /* Clean and invalidate data cache if it is enabled and
     342                 :            :          * that was not already done at boot
     343                 :            :          */
     344                 :            : #if !defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
     345                 :            :         if (SCB->CCR & SCB_CCR_DC_Msk) {
     346                 :            :                 SCB_CleanInvalidateDCache();
     347                 :            :         }
     348                 :            : #endif
     349                 :            : #endif /* CONFIG_NOCACHE_MEMORY */
     350                 :            : 
     351                 :            :         /* Architecture-specific configuration */
     352                 :          1 :         mpu_init();
     353                 :            : 
     354                 :            :         /* Program fixed regions configured at SOC definition. */
     355         [ +  + ]:          3 :         for (r_index = 0U; r_index < mpu_config.num_regions; r_index++) {
     356                 :          2 :                 region_init(r_index, &mpu_config.mpu_regions[r_index]);
     357                 :            :         }
     358                 :            : 
     359                 :            :         /* Update the number of programmed MPU regions. */
     360                 :          1 :         static_regions_num = mpu_config.num_regions;
     361                 :            : 
     362                 :            : 
     363                 :          1 :         arm_core_mpu_enable();
     364                 :            : 
     365                 :            :         /* Program additional fixed flash region for null-pointer
     366                 :            :          * dereferencing detection (debug feature)
     367                 :            :          */
     368                 :            : #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_MPU)
     369                 :            : #if (defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)) && \
     370                 :            :         (CONFIG_FLASH_BASE_ADDRESS > CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE)
     371                 :            : #pragma message "Null-Pointer exception detection cannot be configured on un-mapped flash areas"
     372                 :            : #else
     373                 :            :         const struct z_arm_mpu_partition unmap_region = {
     374                 :            :                 .start = 0x0,
     375                 :            :                 .size = CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE,
     376                 :            : #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
     377                 :            :                 /* Overlapping region (with any permissions)
     378                 :            :                  * will result in fault generation
     379                 :            :                  */
     380                 :            :                 .attr = K_MEM_PARTITION_P_RO_U_NA,
     381                 :            : #else
     382                 :            :                 /* Explicit no-access policy */
     383                 :            :                 .attr = K_MEM_PARTITION_P_NA_U_NA,
     384                 :            : #endif
     385                 :            :         };
     386                 :            : 
     387                 :            :         /* The flash region for null pointer dereferencing detection shall
     388                 :            :          * comply with the regular MPU partition definition restrictions
     389                 :            :          * (size and alignment).
     390                 :            :          */
     391                 :            :         _ARCH_MEM_PARTITION_ALIGN_CHECK(0x0,
     392                 :            :                 CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE);
     393                 :            : 
     394                 :            : #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
     395                 :            :         /* ARMv8-M requires that the area:
     396                 :            :          * 0x0 - CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE
     397                 :            :          * is not unmapped (belongs to a valid MPU region already).
     398                 :            :          */
     399                 :            :         if ((arm_cmse_mpu_region_get(0x0) == -EINVAL) ||
     400                 :            :                 (arm_cmse_mpu_region_get(
     401                 :            :                         CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)
     402                 :            :                 == -EINVAL)) {
     403                 :            :                 __ASSERT(0,
     404                 :            :                         "Null pointer detection page unmapped\n");
     405                 :            :                 }
     406                 :            : #endif
     407                 :            : 
     408                 :            :         if (mpu_configure_region(static_regions_num, &unmap_region) == -EINVAL) {
     409                 :            : 
     410                 :            :                 __ASSERT(0,
     411                 :            :                         "Programming null-pointer detection region failed\n");
     412                 :            :                 return -EINVAL;
     413                 :            :         }
     414                 :            : 
     415                 :            :         static_regions_num++;
     416                 :            : 
     417                 :            : #endif
     418                 :            : #endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_MPU */
     419                 :            : 
     420                 :            :         /* Sanity check for number of regions in Cortex-M0+, M3, and M4. */
     421                 :            : #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \
     422                 :            :         defined(CONFIG_CPU_CORTEX_M3) || \
     423                 :            :         defined(CONFIG_CPU_CORTEX_M4)
     424                 :            :         __ASSERT(
     425                 :            :                 (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == 8,
     426                 :            :                 "Invalid number of MPU regions\n");
     427                 :            : #elif defined(NUM_MPU_REGIONS)
     428         [ -  + ]:          1 :         __ASSERT(
     429                 :            :                 (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos ==
     430                 :            :                 NUM_MPU_REGIONS,
     431                 :            :                 "Invalid number of MPU regions\n");
     432                 :            : #endif /* CORTEX_M0PLUS || CPU_CORTEX_M3 || CPU_CORTEX_M4 */
     433                 :            : 
     434                 :          1 :         return 0;
     435                 :            : }

Generated by: LCOV version 1.14