1 /*
2 * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
3 * Copyright (c) 2022-2024 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 <string.h>
15 #include "array.h"
16 #include "tfm_hal_device_header.h"
17 #include "Driver_Common.h"
18 #include "mmio_defs.h"
19 #include "mpu_armv8m_drv.h"
20 #include "region.h"
21 #include "target_cfg.h"
22 #include "tfm_hal_defs.h"
23 #include "tfm_hal_isolation.h"
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
32 #if TFM_ISOLATION_LEVEL == 3
33 #define PROT_BOUNDARY_VAL \
34 (((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK) | \
35 ((1U << HANDLE_ATTR_SPM_POS) & HANDLE_ATTR_SPM_MASK))
36 #else
37 #define PROT_BOUNDARY_VAL \
38 ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
39 #endif
40
41 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
42 static uint32_t n_configured_regions = 0;
43 struct mpu_armv8m_dev_t dev_mpu_s = {MPU_BASE};
44
45 #ifdef CONFIG_TFM_PARTITION_META
46 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
47 REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
48 #endif /* CONFIG_TFM_PARTITION_META */
49
50 #if TFM_ISOLATION_LEVEL == 3
51 /* Isolation level 3 needs to reserve at lease one MPU region for private data asset. */
52 #define MIN_NR_PRIVATE_DATA_REGION 1
53
54 static uint32_t idx_boundary_handle = 0;
55 REGION_DECLARE(Image$$, PT_RO_START, $$Base);
56 REGION_DECLARE(Image$$, PT_RO_END, $$Base);
57 REGION_DECLARE(Image$$, PT_PRIV_RWZI_START, $$Base);
58 REGION_DECLARE(Image$$, PT_PRIV_RWZI_END, $$Base);
59
60 const static struct mpu_armv8m_region_cfg_t region_cfg[] = {
61 {
62 0, /* will be updated before using */
63 (uint32_t)®ION_NAME(Image$$, PT_RO_START, $$Base),
64 (uint32_t)®ION_NAME(Image$$, PT_RO_END, $$Base) - 1,
65 MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
66 MPU_ARMV8M_XN_EXEC_OK,
67 MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
68 MPU_ARMV8M_SH_NONE,
69 },
70 /* For isolation Level 3, set up static isolation for privileged data.
71 * Unprivileged data is dynamically set during Partition scheduling.
72 */
73 {
74 0, /* will be updated before using */
75 (uint32_t)®ION_NAME(Image$$, PT_PRIV_RWZI_START, $$Base),
76 (uint32_t)®ION_NAME(Image$$, PT_PRIV_RWZI_END, $$Base) - 1,
77 MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
78 MPU_ARMV8M_XN_EXEC_NEVER,
79 MPU_ARMV8M_AP_RW_PRIV_ONLY,
80 MPU_ARMV8M_SH_NONE,
81 },
82 #ifdef CONFIG_TFM_PARTITION_META
83 /* TFM partition metadata pointer region */
84 {
85 0, /* will be updated before using */
86 (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
87 (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
88 MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
89 MPU_ARMV8M_XN_EXEC_NEVER,
90 MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
91 MPU_ARMV8M_SH_NONE
92 }
93 #endif
94 };
95 #else /* TFM_ISOLATION_LEVEL == 3 */
96 /* Isolation level 1&2 do not need to reserve MPU region for private data asset. */
97 #define MIN_NR_PRIVATE_DATA_REGION 0
98
99 REGION_DECLARE(Image$$, ER_VENEER, $$Base);
100 REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
101 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
102 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
103 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
104 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
105 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
106 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
107
108 const struct mpu_armv8m_region_cfg_t region_cfg[] = {
109 /* Veneer region */
110 {
111 0, /* will be updated before using */
112 (uint32_t)®ION_NAME(Image$$, ER_VENEER, $$Base),
113 (uint32_t)®ION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
114 MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
115 MPU_ARMV8M_XN_EXEC_OK,
116 MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
117 MPU_ARMV8M_SH_NONE
118 },
119 /* TFM Core unprivileged code region */
120 {
121 0, /* will be updated before using */
122 (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
123 (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1,
124 MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
125 MPU_ARMV8M_XN_EXEC_OK,
126 MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
127 MPU_ARMV8M_SH_NONE
128 },
129 /* RO region */
130 {
131 0, /* will be updated before using */
132 (uint32_t)®ION_NAME(Image$$, TFM_APP_CODE_START, $$Base),
133 (uint32_t)®ION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1,
134 MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
135 MPU_ARMV8M_XN_EXEC_OK,
136 MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
137 MPU_ARMV8M_SH_NONE
138 },
139 /* RW, ZI and stack as one region */
140 {
141 0, /* will be updated before using */
142 (uint32_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
143 (uint32_t)®ION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1,
144 MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
145 MPU_ARMV8M_XN_EXEC_NEVER,
146 MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
147 MPU_ARMV8M_SH_NONE
148 },
149 #ifdef CONFIG_TFM_PARTITION_META
150 /* TFM partition metadata pointer region */
151 {
152 0, /* will be updated before using */
153 (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
154 (uint32_t)®ION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) -1,
155 MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
156 MPU_ARMV8M_XN_EXEC_NEVER,
157 MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
158 MPU_ARMV8M_SH_NONE
159 }
160 #endif
161 };
162 #endif /* TFM_ISOLATION_LEVEL == 3 */
163 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
164
165 #ifdef TFM_FIH_PROFILE_ON
166 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
fih_verify_mpu_armv8m_region_enabled(const struct mpu_armv8m_dev_t * dev,const struct mpu_armv8m_region_cfg_t * region_cfg,uint32_t region_nr)167 static fih_int fih_verify_mpu_armv8m_region_enabled(
168 const struct mpu_armv8m_dev_t *dev,
169 const struct mpu_armv8m_region_cfg_t *region_cfg,
170 uint32_t region_nr)
171 {
172 MPU_Type *mpu = (MPU_Type *)dev->base;
173
174 uint32_t base_cfg;
175 uint32_t limit_cfg;
176
177 if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0) {
178 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
179 }
180 if ((region_cfg->region_limit & ~MPU_RLAR_LIMIT_Msk) != 0x1F) {
181 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
182 }
183
184 mpu->RNR = region_nr & MPU_RNR_REGION_Msk;
185
186 base_cfg = region_cfg->region_base & MPU_RBAR_BASE_Msk;
187 base_cfg |= (region_cfg->attr_sh << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk;
188 base_cfg |= (region_cfg->attr_access << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk;
189 base_cfg |= (region_cfg->attr_exec << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk;
190 if (mpu->RBAR != base_cfg) {
191 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
192 }
193
194 limit_cfg = (region_cfg->region_limit-1) & MPU_RLAR_LIMIT_Msk;
195 limit_cfg |= (region_cfg->region_attridx << MPU_RLAR_AttrIndx_Pos) &
196 MPU_RLAR_AttrIndx_Msk;
197 limit_cfg |= MPU_RLAR_EN_Msk;
198 if (mpu->RLAR != limit_cfg) {
199 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
200 }
201
202 FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
203 }
204
fih_verify_mpu_armv8m_enabled(struct mpu_armv8m_dev_t * dev,uint32_t privdef_en,uint32_t hfnmi_en)205 static fih_int fih_verify_mpu_armv8m_enabled(struct mpu_armv8m_dev_t *dev,
206 uint32_t privdef_en,
207 uint32_t hfnmi_en)
208 {
209 MPU_Type *mpu = (MPU_Type *)dev->base;
210
211 if (mpu->MAIR0 != ((MPU_ARMV8M_MAIR_ATTR_DEVICE_VAL << MPU_MAIR0_Attr0_Pos) |
212 (MPU_ARMV8M_MAIR_ATTR_CODE_VAL << MPU_MAIR0_Attr1_Pos) |
213 (MPU_ARMV8M_MAIR_ATTR_DATA_VAL << MPU_MAIR0_Attr2_Pos))) {
214 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
215 }
216
217 if (mpu->CTRL != (MPU_CTRL_ENABLE_Msk |
218 (privdef_en ? MPU_CTRL_PRIVDEFENA_Msk : 0) |
219 (hfnmi_en ? MPU_CTRL_HFNMIENA_Msk : 0))) {
220 FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
221 }
222
223 FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
224 }
225 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
226
tfm_hal_verify_static_boundaries(void)227 fih_int tfm_hal_verify_static_boundaries(void)
228 {
229 fih_int fih_rc = FIH_FAILURE;
230
231 /* Verify isolation boundaries between SPE and NSPE */
232 FIH_CALL(fih_verify_sau_and_idau_cfg, fih_rc);
233 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
234 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
235 }
236 FIH_CALL(fih_verify_mpc_cfg, fih_rc);
237 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
238 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
239 }
240 FIH_CALL(fih_verify_ppc_cfg, fih_rc);
241 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
242 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
243 }
244
245 /* Repeat the verification to mitigate instruction skip */
246 FIH_CALL(fih_verify_sau_and_idau_cfg, fih_rc);
247 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
248 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
249 }
250 FIH_CALL(fih_verify_mpc_cfg, fih_rc);
251 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
252 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
253 }
254 FIH_CALL(fih_verify_ppc_cfg, fih_rc);
255 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
256 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
257 }
258
259 /* Verify static isolation boundaries inside SPE */
260 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
261 uint32_t region_nr;
262
263 if ((ARRAY_SIZE(region_cfg) + MIN_NR_PRIVATE_DATA_REGION) > MPU_REGION_NUM) {
264 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
265 }
266
267 for (region_nr = 0; region_nr < ARRAY_SIZE(region_cfg); region_nr++) {
268 /* Verify regions are correctly enabled */
269 FIH_CALL(fih_verify_mpu_armv8m_region_enabled, fih_rc, &dev_mpu_s, ®ion_cfg[region_nr], region_nr);
270 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
271 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
272 }
273 /* Repeat the verification to mitigate instruction skip */
274 FIH_CALL(fih_verify_mpu_armv8m_region_enabled, fih_rc, &dev_mpu_s, ®ion_cfg[region_nr], region_nr);
275 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
276 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
277 }
278 }
279
280 /* Verify MPU is correctly enabled */
281 FIH_CALL(fih_verify_mpu_armv8m_enabled, fih_rc, &dev_mpu_s,
282 PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
283 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
284 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
285 }
286 /* Repeat the verification to mitigate instruction skip */
287 FIH_CALL(fih_verify_mpu_armv8m_enabled, fih_rc, &dev_mpu_s,
288 PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
289 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
290 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
291 }
292 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
293
294 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
295 }
296 #endif /* TFM_FIH_PROFILE_ON */
297
tfm_hal_set_up_static_boundaries(uintptr_t * p_spm_boundary)298 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_set_up_static_boundaries(
299 uintptr_t *p_spm_boundary)
300 {
301 fih_int fih_rc = FIH_FAILURE;
302 /* Set up isolation boundaries between SPE and NSPE */
303 FIH_CALL(sau_and_idau_cfg, fih_rc);
304 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
305 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
306 }
307 FIH_CALL(mpc_init_cfg, fih_rc);
308 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
309 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
310 }
311 FIH_CALL(ppc_init_cfg, fih_rc);
312 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
313 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
314 }
315
316 /* Set up static isolation boundaries inside SPE */
317 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
318 struct mpu_armv8m_region_cfg_t localcfg;
319 int32_t i;
320
321 mpu_armv8m_clean(&dev_mpu_s);
322
323 if ((ARRAY_SIZE(region_cfg) + MIN_NR_PRIVATE_DATA_REGION) > MPU_REGION_NUM) {
324 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
325 }
326
327 /* Update MPU region numbers. The numbers start from 0 and are continuous. */
328 for (i = 0; i < ARRAY_SIZE(region_cfg); i++) {
329 memcpy(&localcfg, ®ion_cfg[i], sizeof(localcfg));
330 /* Update region number */
331 localcfg.region_nr = i;
332 /* Enable regions */
333 FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &localcfg);
334 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
335 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
336 }
337 }
338 n_configured_regions = i;
339
340 /* Enable MPU */
341 FIH_CALL(mpu_armv8m_enable, fih_rc, &dev_mpu_s,
342 PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
343 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
344 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
345 }
346 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
347
348 *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
349
350 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
351 }
352
353 /*
354 * Implementation of tfm_hal_bind_boundary() on AN521:
355 *
356 * The API encodes some attributes into a handle and returns it to SPM.
357 * The attributes include isolation boundaries, privilege, and mmio information.
358 * When scheduler switches running partitions, SPM compares the handle between
359 * partitions to know if boundary update is necessary. If update is required,
360 * SPM passes the handle to platform to do platform settings and update
361 * isolation boundaries.
362 *
363 * The handle should be unique under isolation level 3. The implementation
364 * encodes an index at the highest 8 bits to assure handle uniqueness. While
365 * under isolation level 1/2, handles may not be unique.
366 *
367 * The encoding format assignment:
368 * - For isolation level 3
369 * BIT | 31 24 | 23 20 | ... | 7 4 | 3 0 |
370 * | Unique Index | Region Attr 5 | ... | Region Attr 1 | Base Attr |
371 *
372 * In which the "Region Attr i" is:
373 * BIT | 3 | 2 0 |
374 * | 1: RW, 0: RO | MMIO Index |
375 *
376 * In which the "Base Attr" is:
377 * BIT | 1 | 0 |
378 * | 1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
379 *
380 * - For isolation level 1/2
381 * BIT | 31 2 | 1 | 0 |
382 * | Reserved |1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
383 *
384 * This is a reference implementation on AN521, and may have some limitations.
385 * 1. The maximum number of allowed MMIO regions is 5.
386 * 2. Highest 8 bits are for index. It supports 256 unique handles at most.
387 */
tfm_hal_bind_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t * p_boundary)388 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_bind_boundary(
389 const struct partition_load_info_t *p_ldinf,
390 uintptr_t *p_boundary)
391 {
392 bool privileged;
393 bool ns_agent;
394 uint32_t partition_attrs = 0;
395 #if (CONFIG_TFM_MMIO_REGION_ENABLE == 1) && (TFM_ISOLATION_LEVEL == 2)
396 struct mpu_armv8m_region_cfg_t localcfg;
397 #endif
398 #if CONFIG_TFM_MMIO_REGION_ENABLE == 1
399 uint32_t i, j;
400 const struct asset_desc_t *p_asset;
401 struct platform_data_t *plat_data_ptr;
402 fih_int fih_rc = FIH_FAILURE;
403 #endif /* CONFIG_TFM_MMIO_REGION_ENABLE == 1 */
404
405 if (!p_ldinf || !p_boundary) {
406 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
407 }
408
409 #if TFM_ISOLATION_LEVEL == 1
410 privileged = true;
411 #else
412 privileged = IS_PSA_ROT(p_ldinf);
413 #endif
414
415 ns_agent = IS_NS_AGENT(p_ldinf);
416
417
418 /*
419 * Validate if the named MMIO of partition is allowed by the platform.
420 * Otherwise, skip validation.
421 *
422 * NOTE: Need to add validation of numbered MMIO if platform requires.
423 */
424 #if CONFIG_TFM_MMIO_REGION_ENABLE == 1
425 p_asset = LOAD_INFO_ASSET(p_ldinf);
426
427 for (i = 0; i < p_ldinf->nassets; i++) {
428 if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
429 continue;
430 }
431 for (j = 0; j < ARRAY_SIZE(partition_named_mmio_list); j++) {
432 if (p_asset[i].dev.dev_ref == partition_named_mmio_list[j]) {
433 break;
434 }
435 }
436
437 if (j == ARRAY_SIZE(partition_named_mmio_list)) {
438 /* The MMIO asset is not in the allowed list of platform. */
439 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
440 }
441 /* Assume PPC & MPC settings are required even under level 1 */
442 plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
443 struct platform_data_t *);
444
445 if (plat_data_ptr->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
446 FIH_CALL(ppc_configure_to_secure, fih_rc,
447 plat_data_ptr->periph_ppc_bank,
448 plat_data_ptr->periph_ppc_loc);
449 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
450 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
451 }
452 if (privileged) {
453 FIH_CALL(ppc_clr_secure_unpriv, fih_rc,
454 plat_data_ptr->periph_ppc_bank,
455 plat_data_ptr->periph_ppc_loc);
456 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
457 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
458 }
459 } else {
460 FIH_CALL(ppc_en_secure_unpriv, fih_rc,
461 plat_data_ptr->periph_ppc_bank,
462 plat_data_ptr->periph_ppc_loc);
463 if (fih_not_eq(fih_rc, fih_int_encode(ARM_DRIVER_OK))) {
464 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
465 }
466 }
467 }
468 #if TFM_ISOLATION_LEVEL == 2
469 /*
470 * Static boundaries are set. Set up MPU region for MMIO.
471 * Setup regions for unprivileged assets only.
472 */
473 if (!privileged) {
474 localcfg.region_base = plat_data_ptr->periph_start;
475 localcfg.region_limit = plat_data_ptr->periph_limit;
476 localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
477 localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
478 localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
479 localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
480 localcfg.region_nr = n_configured_regions++;
481
482 FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &localcfg);
483 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
484 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
485 }
486 }
487 #elif TFM_ISOLATION_LEVEL == 3
488 /* Encode MMIO attributes into the "partition_attrs". */
489 partition_attrs <<= HANDLE_PER_ATTR_BITS;
490 partition_attrs |= ((j + 1) & HANDLE_ATTR_INDEX_MASK);
491 if (p_asset[i].attr & ASSET_ATTR_READ_WRITE) {
492 partition_attrs |= HANDLE_ATTR_RW_POS;
493 }
494 #endif
495 }
496 #endif /* CONFIG_TFM_MMIO_REGION_ENABLE == 1 */
497
498 #if TFM_ISOLATION_LEVEL == 3
499 partition_attrs <<= HANDLE_PER_ATTR_BITS;
500 /*
501 * Highest 8 bits are reserved for index, if they are non-zero, MMIO numbers
502 * must have exceeded the limit of 5.
503 */
504 if (partition_attrs & HANDLE_INDEX_MASK) {
505 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
506 }
507 HANDLE_ENCODE_INDEX(partition_attrs, idx_boundary_handle);
508 #endif
509
510 partition_attrs |= ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
511 HANDLE_ATTR_PRIV_MASK;
512 partition_attrs |= ((uint32_t)ns_agent << HANDLE_ATTR_NS_POS) &
513 HANDLE_ATTR_NS_MASK;
514 *p_boundary = (uintptr_t)partition_attrs;
515
516 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
517 }
518
tfm_hal_activate_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t boundary)519 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_activate_boundary(
520 const struct partition_load_info_t *p_ldinf,
521 uintptr_t boundary)
522 {
523 CONTROL_Type ctrl;
524 uint32_t local_handle = (uint32_t)boundary;
525 bool privileged = !!(local_handle & HANDLE_ATTR_PRIV_MASK);
526 #if TFM_ISOLATION_LEVEL == 3
527 bool is_spm = !!(local_handle & HANDLE_ATTR_SPM_MASK);
528 struct mpu_armv8m_region_cfg_t localcfg;
529 uint32_t i;
530 #if CONFIG_TFM_MMIO_REGION_ENABLE == 1
531 uint32_t mmio_index;
532 struct platform_data_t *plat_data_ptr;
533 #endif
534 const struct asset_desc_t *rt_mem;
535 fih_int fih_rc = FIH_FAILURE;
536 #endif /* TFM_ISOLATION_LEVEL == 3 */
537
538 /* Privileged level is required to be set always */
539 ctrl.w = __get_CONTROL();
540 ctrl.b.nPRIV = privileged ? 0 : 1;
541 __set_CONTROL(ctrl.w);
542
543 #if TFM_ISOLATION_LEVEL == 3
544 if (is_spm) {
545 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
546 }
547
548 if (!p_ldinf) {
549 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
550 }
551
552 /* Update regions, for unprivileged partitions only */
553 if (privileged) {
554 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
555 }
556
557 /* Setup runtime memory first */
558 localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
559 localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
560 localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
561 localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
562 rt_mem = LOAD_INFO_ASSET(p_ldinf);
563 /*
564 * AN521 shortcut: The first item is the only runtime memory asset.
565 * Platforms with many memory assets please check this part.
566 */
567 for (i = 0;
568 i < p_ldinf->nassets && !(rt_mem[i].attr & ASSET_ATTR_MMIO);
569 i++) {
570 localcfg.region_nr = n_configured_regions + i;
571 localcfg.region_base = rt_mem[i].mem.start;
572 localcfg.region_limit = rt_mem[i].mem.limit - 1;
573
574 FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &localcfg);
575 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
576 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
577 }
578 }
579
580 i = n_configured_regions + i;
581
582 #if CONFIG_TFM_MMIO_REGION_ENABLE == 1
583 /* Named MMIO part */
584 local_handle = local_handle & (~HANDLE_INDEX_MASK);
585 local_handle >>= HANDLE_PER_ATTR_BITS;
586 mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
587
588 localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
589
590 while (mmio_index && i < MPU_REGION_NUM) {
591 plat_data_ptr =
592 (struct platform_data_t *)partition_named_mmio_list[mmio_index - 1];
593 localcfg.region_nr = i++;
594 localcfg.attr_access = (local_handle & HANDLE_ATTR_RW_POS)?
595 MPU_ARMV8M_AP_RW_PRIV_UNPRIV :
596 MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
597 localcfg.region_base = plat_data_ptr->periph_start;
598 localcfg.region_limit = plat_data_ptr->periph_limit;
599
600 FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &localcfg);
601 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
602 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
603 }
604
605 local_handle >>= HANDLE_PER_ATTR_BITS;
606 mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
607 }
608 #endif
609
610 /* Disable unused regions */
611 while (i < MPU_REGION_NUM) {
612 FIH_CALL(mpu_armv8m_region_disable, fih_rc, &dev_mpu_s, i++);
613 if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
614 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
615 }
616 }
617 #endif /* TFM_ISOLATION_LEVEL == 3 */
618 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
619 }
620
tfm_hal_memory_check(uintptr_t boundary,uintptr_t base,size_t size,uint32_t access_type)621 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_memory_check(
622 uintptr_t boundary, uintptr_t base,
623 size_t size, uint32_t access_type)
624 {
625 int flags = 0;
626
627 /* If size is zero, this indicates an empty buffer and base is ignored */
628 if (size == 0) {
629 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
630 }
631
632 if (!base) {
633 FIH_RET(fih_int_encode(TFM_HAL_ERROR_INVALID_INPUT));
634 }
635
636 if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
637 flags |= CMSE_MPU_READWRITE;
638 } else if (access_type & TFM_HAL_ACCESS_READABLE) {
639 flags |= CMSE_MPU_READ;
640 } else {
641 FIH_RET(fih_int_encode(TFM_HAL_ERROR_INVALID_INPUT));
642 }
643
644 if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
645 flags |= CMSE_MPU_UNPRIV;
646 }
647
648 if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
649 CONTROL_Type ctrl;
650 ctrl.w = __TZ_get_CONTROL_NS();
651 if (ctrl.b.nPRIV == 1) {
652 flags |= CMSE_MPU_UNPRIV;
653 } else {
654 flags &= ~CMSE_MPU_UNPRIV;
655 }
656 flags |= CMSE_NONSECURE;
657 }
658
659 if (cmse_check_address_range((void *)base, size, flags) != NULL) {
660 FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
661 } else {
662 FIH_RET(fih_int_encode(TFM_HAL_ERROR_MEM_FAULT));
663 }
664 }
665
tfm_hal_boundary_need_switch(uintptr_t boundary_from,uintptr_t boundary_to)666 FIH_RET_TYPE(bool) tfm_hal_boundary_need_switch(uintptr_t boundary_from,
667 uintptr_t boundary_to)
668 {
669 if (boundary_from == boundary_to) {
670 FIH_RET(fih_int_encode(false));
671 }
672
673 if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
674 ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
675 FIH_RET(fih_int_encode(false));
676 }
677 FIH_RET(fih_int_encode(true));
678 }
679