/ Drivers / CMSIS / Include / mpu_armv8.h
mpu_armv8.h
  1  /******************************************************************************
  2   * @file     mpu_armv8.h
  3   * @brief    CMSIS MPU API for Armv8-M and Armv8.1-M MPU
  4   * @version  V5.1.3
  5   * @date     03. February 2021
  6   ******************************************************************************/
  7  /*
  8   * Copyright (c) 2017-2021 Arm Limited. All rights reserved.
  9   *
 10   * SPDX-License-Identifier: Apache-2.0
 11   *
 12   * Licensed under the Apache License, Version 2.0 (the License); you may
 13   * not use this file except in compliance with the License.
 14   * You may obtain a copy of the License at
 15   *
 16   * www.apache.org/licenses/LICENSE-2.0
 17   *
 18   * Unless required by applicable law or agreed to in writing, software
 19   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 20   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 21   * See the License for the specific language governing permissions and
 22   * limitations under the License.
 23   */
 24  
 25  #if   defined ( __ICCARM__ )
 26    #pragma system_include         /* treat file as system include file for MISRA check */
 27  #elif defined (__clang__)
 28    #pragma clang system_header    /* treat file as system include file */
 29  #endif
 30  
 31  #ifndef ARM_MPU_ARMV8_H
 32  #define ARM_MPU_ARMV8_H
 33  
 34  /** \brief Attribute for device memory (outer only) */
 35  #define ARM_MPU_ATTR_DEVICE                           ( 0U )
 36  
 37  /** \brief Attribute for non-cacheable, normal memory */
 38  #define ARM_MPU_ATTR_NON_CACHEABLE                    ( 4U )
 39  
 40  /** \brief Attribute for normal memory (outer and inner)
 41  * \param NT Non-Transient: Set to 1 for non-transient data.
 42  * \param WB Write-Back: Set to 1 to use write-back update policy.
 43  * \param RA Read Allocation: Set to 1 to use cache allocation on read miss.
 44  * \param WA Write Allocation: Set to 1 to use cache allocation on write miss.
 45  */
 46  #define ARM_MPU_ATTR_MEMORY_(NT, WB, RA, WA) \
 47    ((((NT) & 1U) << 3U) | (((WB) & 1U) << 2U) | (((RA) & 1U) << 1U) | ((WA) & 1U))
 48  
 49  /** \brief Device memory type non Gathering, non Re-ordering, non Early Write Acknowledgement */
 50  #define ARM_MPU_ATTR_DEVICE_nGnRnE (0U)
 51  
 52  /** \brief Device memory type non Gathering, non Re-ordering, Early Write Acknowledgement */
 53  #define ARM_MPU_ATTR_DEVICE_nGnRE  (1U)
 54  
 55  /** \brief Device memory type non Gathering, Re-ordering, Early Write Acknowledgement */
 56  #define ARM_MPU_ATTR_DEVICE_nGRE   (2U)
 57  
 58  /** \brief Device memory type Gathering, Re-ordering, Early Write Acknowledgement */
 59  #define ARM_MPU_ATTR_DEVICE_GRE    (3U)
 60  
 61  /** \brief Memory Attribute
 62  * \param O Outer memory attributes
 63  * \param I O == ARM_MPU_ATTR_DEVICE: Device memory attributes, else: Inner memory attributes
 64  */
 65  #define ARM_MPU_ATTR(O, I) ((((O) & 0xFU) << 4U) | ((((O) & 0xFU) != 0U) ? ((I) & 0xFU) : (((I) & 0x3U) << 2U)))
 66  
 67  /** \brief Normal memory non-shareable  */
 68  #define ARM_MPU_SH_NON   (0U)
 69  
 70  /** \brief Normal memory outer shareable  */
 71  #define ARM_MPU_SH_OUTER (2U)
 72  
 73  /** \brief Normal memory inner shareable  */
 74  #define ARM_MPU_SH_INNER (3U)
 75  
 76  /** \brief Memory access permissions
 77  * \param RO Read-Only: Set to 1 for read-only memory.
 78  * \param NP Non-Privileged: Set to 1 for non-privileged memory.
 79  */
 80  #define ARM_MPU_AP_(RO, NP) ((((RO) & 1U) << 1U) | ((NP) & 1U))
 81  
 82  /** \brief Region Base Address Register value
 83  * \param BASE The base address bits [31:5] of a memory region. The value is zero extended. Effective address gets 32 byte aligned.
 84  * \param SH Defines the Shareability domain for this memory region.
 85  * \param RO Read-Only: Set to 1 for a read-only memory region.
 86  * \param NP Non-Privileged: Set to 1 for a non-privileged memory region.
 87  * \oaram XN eXecute Never: Set to 1 for a non-executable memory region.
 88  */
 89  #define ARM_MPU_RBAR(BASE, SH, RO, NP, XN) \
 90    (((BASE) & MPU_RBAR_BASE_Msk) | \
 91    (((SH) << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | \
 92    ((ARM_MPU_AP_(RO, NP) << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | \
 93    (((XN) << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk))
 94  
 95  /** \brief Region Limit Address Register value
 96  * \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended.
 97  * \param IDX The attribute index to be associated with this memory region.
 98  */
 99  #define ARM_MPU_RLAR(LIMIT, IDX) \
100    (((LIMIT) & MPU_RLAR_LIMIT_Msk) | \
101    (((IDX) << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \
102    (MPU_RLAR_EN_Msk))
103  
104  #if defined(MPU_RLAR_PXN_Pos)
105    
106  /** \brief Region Limit Address Register with PXN value
107  * \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended.
108  * \param PXN Privileged execute never. Defines whether code can be executed from this privileged region.
109  * \param IDX The attribute index to be associated with this memory region.
110  */
111  #define ARM_MPU_RLAR_PXN(LIMIT, PXN, IDX) \
112    (((LIMIT) & MPU_RLAR_LIMIT_Msk) | \
113    (((PXN) << MPU_RLAR_PXN_Pos) & MPU_RLAR_PXN_Msk) | \
114    (((IDX) << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \
115    (MPU_RLAR_EN_Msk))
116    
117  #endif
118  
119  /**
120  * Struct for a single MPU Region
121  */
122  typedef struct {
123    uint32_t RBAR;                   /*!< Region Base Address Register value */
124    uint32_t RLAR;                   /*!< Region Limit Address Register value */
125  } ARM_MPU_Region_t;
126      
127  /** Enable the MPU.
128  * \param MPU_Control Default access permissions for unconfigured regions.
129  */
130  __STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
131  {
132    __DMB();
133    MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
134  #ifdef SCB_SHCSR_MEMFAULTENA_Msk
135    SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
136  #endif
137    __DSB();
138    __ISB();
139  }
140  
141  /** Disable the MPU.
142  */
143  __STATIC_INLINE void ARM_MPU_Disable(void)
144  {
145    __DMB();
146  #ifdef SCB_SHCSR_MEMFAULTENA_Msk
147    SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
148  #endif
149    MPU->CTRL  &= ~MPU_CTRL_ENABLE_Msk;
150    __DSB();
151    __ISB();
152  }
153  
154  #ifdef MPU_NS
155  /** Enable the Non-secure MPU.
156  * \param MPU_Control Default access permissions for unconfigured regions.
157  */
158  __STATIC_INLINE void ARM_MPU_Enable_NS(uint32_t MPU_Control)
159  {
160    __DMB();
161    MPU_NS->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
162  #ifdef SCB_SHCSR_MEMFAULTENA_Msk
163    SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
164  #endif
165    __DSB();
166    __ISB();
167  }
168  
169  /** Disable the Non-secure MPU.
170  */
171  __STATIC_INLINE void ARM_MPU_Disable_NS(void)
172  {
173    __DMB();
174  #ifdef SCB_SHCSR_MEMFAULTENA_Msk
175    SCB_NS->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
176  #endif
177    MPU_NS->CTRL  &= ~MPU_CTRL_ENABLE_Msk;
178    __DSB();
179    __ISB();
180  }
181  #endif
182  
183  /** Set the memory attribute encoding to the given MPU.
184  * \param mpu Pointer to the MPU to be configured.
185  * \param idx The attribute index to be set [0-7]
186  * \param attr The attribute value to be set.
187  */
188  __STATIC_INLINE void ARM_MPU_SetMemAttrEx(MPU_Type* mpu, uint8_t idx, uint8_t attr)
189  {
190    const uint8_t reg = idx / 4U;
191    const uint32_t pos = ((idx % 4U) * 8U);
192    const uint32_t mask = 0xFFU << pos;
193    
194    if (reg >= (sizeof(mpu->MAIR) / sizeof(mpu->MAIR[0]))) {
195      return; // invalid index
196    }
197    
198    mpu->MAIR[reg] = ((mpu->MAIR[reg] & ~mask) | ((attr << pos) & mask));
199  }
200  
201  /** Set the memory attribute encoding.
202  * \param idx The attribute index to be set [0-7]
203  * \param attr The attribute value to be set.
204  */
205  __STATIC_INLINE void ARM_MPU_SetMemAttr(uint8_t idx, uint8_t attr)
206  {
207    ARM_MPU_SetMemAttrEx(MPU, idx, attr);
208  }
209  
210  #ifdef MPU_NS
211  /** Set the memory attribute encoding to the Non-secure MPU.
212  * \param idx The attribute index to be set [0-7]
213  * \param attr The attribute value to be set.
214  */
215  __STATIC_INLINE void ARM_MPU_SetMemAttr_NS(uint8_t idx, uint8_t attr)
216  {
217    ARM_MPU_SetMemAttrEx(MPU_NS, idx, attr);
218  }
219  #endif
220  
221  /** Clear and disable the given MPU region of the given MPU.
222  * \param mpu Pointer to MPU to be used.
223  * \param rnr Region number to be cleared.
224  */
225  __STATIC_INLINE void ARM_MPU_ClrRegionEx(MPU_Type* mpu, uint32_t rnr)
226  {
227    mpu->RNR = rnr;
228    mpu->RLAR = 0U;
229  }
230  
231  /** Clear and disable the given MPU region.
232  * \param rnr Region number to be cleared.
233  */
234  __STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
235  {
236    ARM_MPU_ClrRegionEx(MPU, rnr);
237  }
238  
239  #ifdef MPU_NS
240  /** Clear and disable the given Non-secure MPU region.
241  * \param rnr Region number to be cleared.
242  */
243  __STATIC_INLINE void ARM_MPU_ClrRegion_NS(uint32_t rnr)
244  {  
245    ARM_MPU_ClrRegionEx(MPU_NS, rnr);
246  }
247  #endif
248  
249  /** Configure the given MPU region of the given MPU.
250  * \param mpu Pointer to MPU to be used.
251  * \param rnr Region number to be configured.
252  * \param rbar Value for RBAR register.
253  * \param rlar Value for RLAR register.
254  */   
255  __STATIC_INLINE void ARM_MPU_SetRegionEx(MPU_Type* mpu, uint32_t rnr, uint32_t rbar, uint32_t rlar)
256  {
257    mpu->RNR = rnr;
258    mpu->RBAR = rbar;
259    mpu->RLAR = rlar;
260  }
261  
262  /** Configure the given MPU region.
263  * \param rnr Region number to be configured.
264  * \param rbar Value for RBAR register.
265  * \param rlar Value for RLAR register.
266  */   
267  __STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rnr, uint32_t rbar, uint32_t rlar)
268  {
269    ARM_MPU_SetRegionEx(MPU, rnr, rbar, rlar);
270  }
271  
272  #ifdef MPU_NS
273  /** Configure the given Non-secure MPU region.
274  * \param rnr Region number to be configured.
275  * \param rbar Value for RBAR register.
276  * \param rlar Value for RLAR register.
277  */   
278  __STATIC_INLINE void ARM_MPU_SetRegion_NS(uint32_t rnr, uint32_t rbar, uint32_t rlar)
279  {
280    ARM_MPU_SetRegionEx(MPU_NS, rnr, rbar, rlar);  
281  }
282  #endif
283  
284  /** Memcpy with strictly ordered memory access, e.g. used by code in ARM_MPU_LoadEx()
285  * \param dst Destination data is copied to.
286  * \param src Source data is copied from.
287  * \param len Amount of data words to be copied.
288  */
289  __STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
290  {
291    uint32_t i;
292    for (i = 0U; i < len; ++i) 
293    {
294      dst[i] = src[i];
295    }
296  }
297  
298  /** Load the given number of MPU regions from a table to the given MPU.
299  * \param mpu Pointer to the MPU registers to be used.
300  * \param rnr First region number to be configured.
301  * \param table Pointer to the MPU configuration table.
302  * \param cnt Amount of regions to be configured.
303  */
304  __STATIC_INLINE void ARM_MPU_LoadEx(MPU_Type* mpu, uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) 
305  {
306    const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
307    if (cnt == 1U) {
308      mpu->RNR = rnr;
309      ARM_MPU_OrderedMemcpy(&(mpu->RBAR), &(table->RBAR), rowWordSize);
310    } else {
311      uint32_t rnrBase   = rnr & ~(MPU_TYPE_RALIASES-1U);
312      uint32_t rnrOffset = rnr % MPU_TYPE_RALIASES;
313      
314      mpu->RNR = rnrBase;
315      while ((rnrOffset + cnt) > MPU_TYPE_RALIASES) {
316        uint32_t c = MPU_TYPE_RALIASES - rnrOffset;
317        ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), c*rowWordSize);
318        table += c;
319        cnt -= c;
320        rnrOffset = 0U;
321        rnrBase += MPU_TYPE_RALIASES;
322        mpu->RNR = rnrBase;
323      }
324      
325      ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), cnt*rowWordSize);
326    }
327  }
328  
329  /** Load the given number of MPU regions from a table.
330  * \param rnr First region number to be configured.
331  * \param table Pointer to the MPU configuration table.
332  * \param cnt Amount of regions to be configured.
333  */
334  __STATIC_INLINE void ARM_MPU_Load(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) 
335  {
336    ARM_MPU_LoadEx(MPU, rnr, table, cnt);
337  }
338  
339  #ifdef MPU_NS
340  /** Load the given number of MPU regions from a table to the Non-secure MPU.
341  * \param rnr First region number to be configured.
342  * \param table Pointer to the MPU configuration table.
343  * \param cnt Amount of regions to be configured.
344  */
345  __STATIC_INLINE void ARM_MPU_Load_NS(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt) 
346  {
347    ARM_MPU_LoadEx(MPU_NS, rnr, table, cnt);
348  }
349  #endif
350  
351  #endif
352