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