1 /*
2  * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
3  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
4  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5  * reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 #include <arm_cmse.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include "array.h"
15 #include "tfm_hal_device_header.h"
16 #include "Driver_Common.h"
17 #include "mmio_defs.h"
18 #include "mpu_armv8m_drv.h"
19 #include "region.h"
20 #include "target_cfg.h"
21 #include "tfm_hal_defs.h"
22 #include "tfm_hal_isolation.h"
23 #include "tfm_peripherals_def.h"
24 #include "load/partition_defs.h"
25 #include "load/asset_defs.h"
26 #include "load/spm_load_api.h"
27 
28 /* It can be retrieved from the MPU_TYPE register. */
29 #define MPU_REGION_NUM                  8
30 
31 #if TFM_ISOLATION_LEVEL == 3
32 #define PROT_BOUNDARY_VAL \
33     (((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK) | \
34      ((1U << HANDLE_ATTR_SPM_POS) & HANDLE_ATTR_SPM_MASK))
35 #else
36 #define PROT_BOUNDARY_VAL \
37     ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
38 #endif
39 
40 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
41 static uint32_t n_configured_regions = 0;
42 struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
43 
44 #ifdef CONFIG_TFM_PARTITION_META
45 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
46 REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
47 #endif
48 
49 #if TFM_ISOLATION_LEVEL == 3
50 static uint32_t idx_boundary_handle = 0;
51 REGION_DECLARE(Image$$, PT_RO_START, $$Base);
52 REGION_DECLARE(Image$$, PT_RO_END, $$Base);
53 REGION_DECLARE(Image$$, PT_PRIV_RWZI_START, $$Base);
54 REGION_DECLARE(Image$$, PT_PRIV_RWZI_END, $$Base);
55 
56 static struct mpu_armv8m_region_cfg_t isolation_regions[] = {
57     {
58         0, /* will be updated before using */
59         (uint32_t)&REGION_NAME(Image$$, PT_RO_START, $$Base),
60         (uint32_t)&REGION_NAME(Image$$, PT_RO_END, $$Base) - 1,
61         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
62         MPU_ARMV8M_XN_EXEC_OK,
63         MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
64         MPU_ARMV8M_SH_NONE,
65     },
66     /* For isolation Level 3, set up static isolation for privileged data.
67      * Unprivileged data is dynamically set during Partition scheduling.
68      */
69     {
70         0, /* will be updated before using */
71         (uint32_t)&REGION_NAME(Image$$, PT_PRIV_RWZI_START, $$Base),
72         (uint32_t)&REGION_NAME(Image$$, PT_PRIV_RWZI_END, $$Base) - 1,
73         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
74         MPU_ARMV8M_XN_EXEC_NEVER,
75         MPU_ARMV8M_AP_RW_PRIV_ONLY,
76         MPU_ARMV8M_SH_NONE,
77     },
78 #ifdef CONFIG_TFM_PARTITION_META
79     {
80         0, /* will be updated before using */
81         (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
82         (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
83         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
84         MPU_ARMV8M_XN_EXEC_NEVER,
85         MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
86         MPU_ARMV8M_SH_NONE,
87     }
88 #endif
89 };
90 #else /* TFM_ISOLATION_LEVEL == 3 */
91 
92 REGION_DECLARE(Image$$, ER_VENEER, $$Base);
93 REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
94 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
95 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
96 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
97 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
98 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
99 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
100 
101 #endif /* TFM_ISOLATION_LEVEL == 3 */
102 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
103 
tfm_hal_set_up_static_boundaries(uintptr_t * p_spm_boundary)104 enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
105                                             uintptr_t *p_spm_boundary)
106 {
107     /* Set up isolation boundaries between SPE and NSPE */
108     sau_and_idau_cfg();
109 
110     if (mpc_init_cfg() != ARM_DRIVER_OK) {
111         return TFM_HAL_ERROR_GENERIC;
112     }
113 
114     if (ppc_init_cfg() != ARM_DRIVER_OK) {
115         return TFM_HAL_ERROR_GENERIC;
116     }
117 
118     /* Set up static isolation boundaries inside SPE */
119 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
120 
121     mpu_armv8m_clean(&dev_mpu_s);
122 #if TFM_ISOLATION_LEVEL == 3
123     int32_t i;
124 
125     /*
126      * Update MPU region numbers. The numbers start from 0 and are continuous.
127      * Under isolation level3, at lease one MPU region is reserved for private
128      * data asset.
129      */
130     if (ARRAY_SIZE(isolation_regions) >= MPU_REGION_NUM) {
131         return TFM_HAL_ERROR_GENERIC;
132     }
133     for (i = 0; i < ARRAY_SIZE(isolation_regions); i++) {
134         /* Update region number */
135         isolation_regions[i].region_nr = i;
136         /* Enable regions */
137         if (mpu_armv8m_region_enable(&dev_mpu_s, &isolation_regions[i])
138                                                              != MPU_ARMV8M_OK) {
139             return TFM_HAL_ERROR_GENERIC;
140         }
141     }
142     n_configured_regions = i;
143 #else /* TFM_ISOLATION_LEVEL == 3 */
144     struct mpu_armv8m_region_cfg_t region_cfg;
145 
146     /* Veneer region */
147     region_cfg.region_nr = n_configured_regions;
148     region_cfg.region_base = (uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base);
149     region_cfg.region_limit =
150         (uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1;
151     region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
152     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
153     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
154     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
155     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
156         return TFM_HAL_ERROR_GENERIC;
157     }
158     n_configured_regions++;
159 
160     /* TFM Core unprivileged code region */
161     region_cfg.region_nr = n_configured_regions;
162     region_cfg.region_base =
163         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
164     region_cfg.region_limit =
165         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1;
166     region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
167     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
168     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
169     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
170     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
171         return TFM_HAL_ERROR_GENERIC;
172     }
173     n_configured_regions++;
174 
175     /* RO region */
176     region_cfg.region_nr = n_configured_regions;
177     region_cfg.region_base =
178         (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
179     region_cfg.region_limit =
180         (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1;
181     region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_CODE_IDX;
182     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
183     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
184     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
185     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
186         return TFM_HAL_ERROR_GENERIC;
187     }
188     n_configured_regions++;
189 
190     /* RW, ZI and stack as one region */
191     region_cfg.region_nr = n_configured_regions;
192     region_cfg.region_base =
193         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
194     region_cfg.region_limit =
195         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1;
196     region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
197     region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
198     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
199     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
200     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
201         return TFM_HAL_ERROR_GENERIC;
202     }
203     n_configured_regions++;
204 
205 #ifdef CONFIG_TFM_PARTITION_META
206     /* TFM partition metadata pointer region */
207     region_cfg.region_nr = n_configured_regions;
208     region_cfg.region_base =
209      (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
210     region_cfg.region_limit =
211      (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1;
212     region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
213     region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
214     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
215     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
216     if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
217         return TFM_HAL_ERROR_GENERIC;
218     }
219     n_configured_regions++;
220 #endif /* CONFIG_TFM_PARTITION_META */
221 #endif /* TFM_ISOLATION_LEVEL == 3 */
222 
223     /* Enable MPU */
224     if (mpu_armv8m_enable(&dev_mpu_s,
225                           PRIVILEGED_DEFAULT_ENABLE,
226                           HARDFAULT_NMI_ENABLE) != MPU_ARMV8M_OK) {
227         return TFM_HAL_ERROR_GENERIC;
228     }
229 #endif
230 
231     *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
232 
233     return TFM_HAL_SUCCESS;
234 }
235 
236 /*
237  * Implementation of tfm_hal_bind_boundary() on MUSCA_B1:
238  *
239  * The API encodes some attributes into a handle and returns it to SPM.
240  * The attributes include isolation boundaries, privilege, and MMIO information.
241  * When scheduler switches running partitions, SPM compares the handle between
242  * partitions to know if boundary update is necessary. If update is required,
243  * SPM passes the handle to platform to do platform settings and update
244  * isolation boundaries.
245  *
246  * The handle should be unique under isolation level 3. The implementation
247  * encodes an index at the highest 8 bits to assure handle uniqueness. While
248  * under isolation level 1/2, handles may not be unique.
249  *
250  * The encoding format assignment:
251  * - For isolation level 3
252  *      BIT | 31        24 | 23         20 | ... | 7           4 | 3       0 |
253  *          | Unique Index | Region Attr 5 | ... | Region Attr 1 | Base Attr |
254  *
255  *      In which the "Region Attr i" is:
256  *      BIT |       3      | 2        0 |
257  *          | 1: RW, 0: RO | MMIO Index |
258  *
259  *      In which the "Base Attr" is:
260  *      BIT |               1                |                           0                     |
261  *          | 1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
262  *
263  * - For isolation level 1/2
264  *      BIT | 31     2 |              1                |                           0                     |
265  *          | Reserved |1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
266  *
267  * This is a reference implementation on MUSCA_B1, and may have some
268  * limitations.
269  * 1. The maximum number of allowed MMIO regions is 5.
270  * 2. Highest 8 bits are for index. It supports 256 unique handles at most.
271  */
tfm_hal_bind_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t * p_boundary)272 enum tfm_hal_status_t tfm_hal_bind_boundary(
273                                     const struct partition_load_info_t *p_ldinf,
274                                     uintptr_t *p_boundary)
275 {
276     uint32_t i, j;
277     bool privileged;
278     bool ns_agent;
279     uint32_t partition_attrs = 0;
280     const struct asset_desc_t *p_asset;
281     struct platform_data_t *plat_data_ptr;
282 #if TFM_ISOLATION_LEVEL == 2
283     struct mpu_armv8m_region_cfg_t localcfg;
284 #endif
285 
286     if (!p_ldinf || !p_boundary) {
287         return TFM_HAL_ERROR_GENERIC;
288     }
289 
290 #if TFM_ISOLATION_LEVEL == 1
291     privileged = true;
292 #else
293     privileged = IS_PSA_ROT(p_ldinf);
294 #endif
295 
296     ns_agent = IS_NS_AGENT(p_ldinf);
297     p_asset = LOAD_INFO_ASSET(p_ldinf);
298 
299     /*
300      * Validate if the named MMIO of partition is allowed by the platform.
301      * Otherwise, skip validation.
302      *
303      * NOTE: Need to add validation of numbered MMIO if platform requires.
304      */
305     for (i = 0; i < p_ldinf->nassets; i++) {
306         if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
307             continue;
308         }
309         for (j = 0; j < ARRAY_SIZE(partition_named_mmio_list); j++) {
310             if (p_asset[i].dev.dev_ref == partition_named_mmio_list[j]) {
311                 break;
312             }
313         }
314 
315         if (j == ARRAY_SIZE(partition_named_mmio_list)) {
316             /* The MMIO asset is not in the allowed list of platform. */
317             return TFM_HAL_ERROR_GENERIC;
318         }
319         /* Assume PPC & MPC settings are required even under level 1 */
320         plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
321                                          struct platform_data_t *);
322 
323         if (plat_data_ptr->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
324             ppc_configure_to_secure(plat_data_ptr->periph_ppc_bank,
325                                     plat_data_ptr->periph_ppc_loc);
326             if (privileged) {
327                 ppc_clr_secure_unpriv(plat_data_ptr->periph_ppc_bank,
328                                       plat_data_ptr->periph_ppc_loc);
329             } else {
330                 ppc_en_secure_unpriv(plat_data_ptr->periph_ppc_bank,
331                                      plat_data_ptr->periph_ppc_loc);
332             }
333         }
334 
335 #if TFM_ISOLATION_LEVEL == 2
336         /*
337          * Static boundaries are set. Set up MPU region for MMIO.
338          * Setup regions for unprivileged assets only.
339          */
340         if (!privileged) {
341             localcfg.region_base = plat_data_ptr->periph_start;
342             localcfg.region_limit = plat_data_ptr->periph_limit;
343             localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
344             localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
345             localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
346             localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
347             localcfg.region_nr = n_configured_regions++;
348 
349             if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg)
350                 != MPU_ARMV8M_OK) {
351                 return TFM_HAL_ERROR_GENERIC;
352             }
353         }
354 #elif TFM_ISOLATION_LEVEL == 3
355         /* Encode MMIO attributes into the "partition_attrs". */
356         partition_attrs <<= HANDLE_PER_ATTR_BITS;
357         partition_attrs |= ((j + 1) & HANDLE_ATTR_INDEX_MASK);
358         if (p_asset[i].attr & ASSET_ATTR_READ_WRITE) {
359             partition_attrs |= HANDLE_ATTR_RW_POS;
360         }
361 #endif
362     }
363 
364 #if TFM_ISOLATION_LEVEL == 3
365     partition_attrs <<= HANDLE_PER_ATTR_BITS;
366     /*
367      * Highest 8 bits are reserved for index, if they are non-zero, MMIO numbers
368      * must have exceeded the limit of 5.
369      */
370     if (partition_attrs & HANDLE_INDEX_MASK) {
371         return TFM_HAL_ERROR_GENERIC;
372     }
373     HANDLE_ENCODE_INDEX(partition_attrs, idx_boundary_handle);
374 #endif
375 
376     partition_attrs |= ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
377                         HANDLE_ATTR_PRIV_MASK;
378     partition_attrs |= ((uint32_t)ns_agent << HANDLE_ATTR_NS_POS) &
379                         HANDLE_ATTR_NS_MASK;
380     *p_boundary = (uintptr_t)partition_attrs;
381 
382     return TFM_HAL_SUCCESS;
383 }
384 
tfm_hal_activate_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t boundary)385 enum tfm_hal_status_t tfm_hal_activate_boundary(
386                              const struct partition_load_info_t *p_ldinf,
387                              uintptr_t boundary)
388 {
389     CONTROL_Type ctrl;
390     uint32_t local_handle = (uint32_t)boundary;
391     bool privileged = !!(local_handle & HANDLE_ATTR_PRIV_MASK);
392 #if TFM_ISOLATION_LEVEL == 3
393     bool is_spm = !!(local_handle & HANDLE_ATTR_SPM_MASK);
394     struct mpu_armv8m_region_cfg_t localcfg;
395     uint32_t i, mmio_index;
396     struct platform_data_t *plat_data_ptr;
397     const struct asset_desc_t *rt_mem;
398 #endif
399 
400     /* Privileged level is required to be set always */
401     ctrl.w = __get_CONTROL();
402     ctrl.b.nPRIV = privileged ? 0 : 1;
403     __set_CONTROL(ctrl.w);
404 
405 #if TFM_ISOLATION_LEVEL == 3
406     if (is_spm) {
407         FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
408     }
409 
410     if (!p_ldinf) {
411         return TFM_HAL_ERROR_GENERIC;
412     }
413 
414     /* Update regions, for unprivileged partitions only */
415     if (privileged) {
416         return TFM_HAL_SUCCESS;
417     }
418 
419     /* Setup runtime memory first */
420     localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
421     localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
422     localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
423     localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
424     rt_mem = LOAD_INFO_ASSET(p_ldinf);
425     /*
426      * MUSCA_B1 shortcut: The first item is the only runtime memory asset.
427      * Platforms with many memory assets please check this part.
428      */
429     for (i = 0;
430          i < p_ldinf->nassets && !(rt_mem[i].attr & ASSET_ATTR_MMIO);
431          i++) {
432         localcfg.region_nr = n_configured_regions + i;
433         localcfg.region_base = rt_mem[i].mem.start;
434         localcfg.region_limit = rt_mem[i].mem.limit - 1;
435 
436         if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) {
437             return TFM_HAL_ERROR_GENERIC;
438         }
439     }
440 
441     /* Named MMIO part */
442     local_handle = local_handle & (~HANDLE_INDEX_MASK);
443     local_handle >>= HANDLE_PER_ATTR_BITS;
444     mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
445 
446     localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
447 
448     i = n_configured_regions + i;
449     while (mmio_index && i < MPU_REGION_NUM) {
450         plat_data_ptr =
451           (struct platform_data_t *)partition_named_mmio_list[mmio_index - 1];
452         localcfg.region_nr = i++;
453         localcfg.attr_access = (local_handle & HANDLE_ATTR_RW_POS)?
454                             MPU_ARMV8M_AP_RW_PRIV_UNPRIV :
455                             MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
456         localcfg.region_base = plat_data_ptr->periph_start;
457         localcfg.region_limit = plat_data_ptr->periph_limit;
458 
459         if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) {
460             return TFM_HAL_ERROR_GENERIC;
461         }
462 
463         local_handle >>= HANDLE_PER_ATTR_BITS;
464         mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
465     }
466 
467     /* Disable unused regions */
468     while (i < MPU_REGION_NUM) {
469         if (mpu_armv8m_region_disable(&dev_mpu_s, i++)!= MPU_ARMV8M_OK) {
470             return TFM_HAL_ERROR_GENERIC;
471         }
472     }
473 #endif
474     return TFM_HAL_SUCCESS;
475 }
476 
tfm_hal_memory_check(uintptr_t boundary,uintptr_t base,size_t size,uint32_t access_type)477 enum tfm_hal_status_t tfm_hal_memory_check(uintptr_t boundary, uintptr_t base,
478                                            size_t size, uint32_t access_type)
479 {
480     int flags = 0;
481 
482     /* If size is zero, this indicates an empty buffer and base is ignored */
483     if (size == 0) {
484         return TFM_HAL_SUCCESS;
485     }
486 
487     if (!base) {
488         return TFM_HAL_ERROR_INVALID_INPUT;
489     }
490 
491     if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
492         flags |= CMSE_MPU_READWRITE;
493     } else if (access_type & TFM_HAL_ACCESS_READABLE) {
494         flags |= CMSE_MPU_READ;
495     } else {
496         return TFM_HAL_ERROR_INVALID_INPUT;
497     }
498 
499     if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
500         flags |= CMSE_MPU_UNPRIV;
501     }
502 
503     if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
504         CONTROL_Type ctrl;
505         ctrl.w = __TZ_get_CONTROL_NS();
506         if (ctrl.b.nPRIV == 1) {
507             flags |= CMSE_MPU_UNPRIV;
508         } else {
509             flags &= ~CMSE_MPU_UNPRIV;
510         }
511         flags |= CMSE_NONSECURE;
512     }
513 
514     if (cmse_check_address_range((void *)base, size, flags) != NULL) {
515         return TFM_HAL_SUCCESS;
516     } else {
517         return TFM_HAL_ERROR_MEM_FAULT;
518     }
519 }
520 
tfm_hal_boundary_need_switch(uintptr_t boundary_from,uintptr_t boundary_to)521 bool tfm_hal_boundary_need_switch(uintptr_t boundary_from,
522                                   uintptr_t boundary_to)
523 {
524     if (boundary_from == boundary_to) {
525         return false;
526     }
527 
528     if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
529         ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
530         return false;
531     }
532     return true;
533 }
534