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)®ION_NAME(Image$$, PT_RO_START, $$Base),
48 (uint32_t)®ION_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)®ION_NAME(Image$$, PT_PRIV_RWZI_START, $$Base),
60 (uint32_t)®ION_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)®ION_NAME(Image$$, ER_VENEER, $$Base);
131 region_cfg.region_limit =
132 (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base);
152 region_cfg.region_limit =
153 (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
173 region_cfg.region_limit =
174 (uint32_t)®ION_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, ®ion_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)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
194 region_cfg.region_limit =
195 (uint32_t)®ION_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, ®ion_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, ®ion_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)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
235 region_cfg.region_limit =
236 (uint32_t)®ION_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, ®ion_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