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)&REGION_NAME(Image$$, PT_RO_START, $$Base),
64         (uint32_t)&REGION_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)&REGION_NAME(Image$$, PT_PRIV_RWZI_START, $$Base),
76         (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
87         (uint32_t)&REGION_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)&REGION_NAME(Image$$, ER_VENEER, $$Base),
113         (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
123         (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base),
133         (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
143         (uint32_t)&REGION_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)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
154         (uint32_t)&REGION_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, &region_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, &region_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, &region_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