1 /*
2  *  SPDX-License-Identifier: BSD-3-Clause
3  *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4  *
5  */
6 
7 #include <arm_cmse.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11 #include <stdbool.h>
12 #include "array.h"
13 #include "tfm_hal_device_header.h"
14 #include "region.h"
15 #include "armv8m_mpu.h"
16 #include "target_cfg.h"
17 #include "tfm_hal_defs.h"
18 #include "tfm_hal_isolation.h"
19 #include "tfm_peripherals_def.h"
20 #include "load/spm_load_api.h"
21 
22 #define PROT_BOUNDARY_VAL \
23     ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
24 /* Boundary handle binding macros. */
25 #define HANDLE_ATTR_PRIV_POS            1U
26 #define HANDLE_ATTR_PRIV_MASK           (0x1UL << HANDLE_ATTR_PRIV_POS)
27 #define HANDLE_ATTR_NS_POS              0U
28 #define HANDLE_ATTR_NS_MASK             (0x1UL << HANDLE_ATTR_NS_POS)
29 
30 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
31 static uint32_t n_configured_regions = 0;
32 
33 #ifdef CONFIG_TFM_USE_TRUSTZONE
34 REGION_DECLARE(Image$$, ER_VENEER, $$Base);
35 REGION_DECLARE(Image$$, VENEER_ALIGN, $$Limit);
36 #endif /* CONFIG_TFM_USE_TRUSTZONE */
37 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
38 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
39 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
40 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
41 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
42 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
43 #ifdef CONFIG_TFM_PARTITION_META
44 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
45 REGION_DECLARE(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit);
46 #endif /* CONFIG_TFM_PARTITION_META */
47 
48 #define ARM_MPU_NON_TRANSIENT        ( 1U )
49 #define ARM_MPU_TRANSIENT            ( 0U )
50 #define ARM_MPU_WRITE_BACK           ( 1U )
51 #define ARM_MPU_WRITE_THROUGH        ( 0U )
52 #define ARM_MPU_READ_ALLOCATE        ( 1U )
53 #define ARM_MPU_NON_READ_ALLOCATE    ( 0U )
54 #define ARM_MPU_WRITE_ALLOCATE       ( 1U )
55 #define ARM_MPU_NON_WRITE_ALLOCATE   ( 0U )
56 #define ARM_MPU_READ_ONLY            ( 1U )
57 #define ARM_MPU_READ_WRITE           ( 0U )
58 #define ARM_MPU_UNPRIVILEGED         ( 1U )
59 #define ARM_MPU_PRIVILEGED           ( 0U )
60 #define ARM_MPU_EXECUTE_NEVER        ( 1U )
61 #define ARM_MPU_EXECUTE_OK           ( 0U )
62 #define ARM_MPU_PRIVILEGE_EXECUTE_NEVER  ( 1U )
63 #define ARM_MPU_PRIVILEGE_EXECUTE_OK     ( 0U )
64 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
65 
tfm_hal_set_up_static_boundaries(uintptr_t * p_spm_boundary)66 enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
67                                             uintptr_t *p_spm_boundary)
68 {
69 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
70 const ARM_MPU_Region_t mpu_region_attributes[] = {
71 #ifdef CONFIG_TFM_USE_TRUSTZONE
72     /* TFM Veneer region (Bootrom SGs are not included)
73      * Region Number 0, Non-shareable, Read-Only, Non-Privileged, Executable,
74      * Privilege Executable - if PXN available, Attribute set: 0
75      */
76     {
77         ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base),
78                      ARM_MPU_SH_NON,
79                      ARM_MPU_READ_ONLY,
80                      ARM_MPU_UNPRIVILEGED,
81                      ARM_MPU_EXECUTE_OK),
82         #ifdef TFM_PXN_ENABLE
83         ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
84                          ARM_MPU_PRIVILEGE_EXECUTE_OK,
85                          0)
86         #else
87         ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
88                      0)
89         #endif
90     },
91 #endif /* CONFIG_TFM_USE_TRUSTZONE */
92     /* TFM Core unprivileged code region
93      * Region Number 1, Non-shareable, Read-Only, Non-Privileged, Executable,
94      * Privilege Executable - if PXN available, Attribute set: 0
95      */
96     {
97         ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
98                      ARM_MPU_SH_NON,
99                      ARM_MPU_READ_ONLY,
100                      ARM_MPU_UNPRIVILEGED,
101                      ARM_MPU_EXECUTE_OK),
102         #ifdef TFM_PXN_ENABLE
103         ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1,
104                          ARM_MPU_PRIVILEGE_EXECUTE_OK,
105                          0)
106         #else
107         ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit) - 1,
108                      0)
109         #endif
110     },
111     /* RO region
112      * Region Number 2, Non-shareable, Read-Only, Non-Privileged, Executable,
113      * PXN depends on isolation level, Attribute set: 0
114      */
115     {
116         ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base),
117                      ARM_MPU_SH_NON,
118                      ARM_MPU_READ_ONLY,
119                      ARM_MPU_UNPRIVILEGED,
120                      ARM_MPU_EXECUTE_OK),
121         #ifdef TFM_PXN_ENABLE
122         ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1,
123             #if TFM_ISOLATION_LEVEL == 1
124                          ARM_MPU_PRIVILEGE_EXECUTE_OK,
125             #else
126                          ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
127             #endif
128                          0)
129         #else
130         ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base) - 1,
131                      0)
132         #endif
133     },
134     /* RW, ZI and stack as one region
135      * Region Number 3, Non-shareable, Read-Write, Non-Privileged, Execute Never
136      * Attribute set: 1, Privilege Execute Never - if PXN available
137      */
138     {
139         ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
140                      ARM_MPU_SH_NON,
141                      ARM_MPU_READ_WRITE,
142                      ARM_MPU_UNPRIVILEGED,
143                      ARM_MPU_EXECUTE_NEVER),
144         #ifdef TFM_PXN_ENABLE
145         ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1,
146                          ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
147                          1)
148         #else
149         ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base) - 1,
150                      1)
151         #endif
152     },
153 #ifdef CONFIG_TFM_PARTITION_META
154     /* TFM partition metadata pointer region
155      * Region Number 4, Non-shareable, Read-Write, Non-Privileged, Execute Never
156      * Attribute set: 1, Privilege Execute Never - if PXN available
157      */
158     {
159         ARM_MPU_RBAR((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base),
160                      ARM_MPU_SH_NON,
161                      ARM_MPU_READ_WRITE,
162                      ARM_MPU_UNPRIVILEGED,
163                      ARM_MPU_EXECUTE_NEVER),
164         #ifdef TFM_PXN_ENABLE
165         ARM_MPU_RLAR_PXN((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
166                          ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
167                          1)
168         #else
169         ARM_MPU_RLAR((uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR_END, $$ZI$$Limit) - 1,
170                      1)
171         #endif
172     },
173 #endif
174 };
175     ARM_MPU_Region_t localcfg;
176 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
177 
178     /* Set up isolation boundaries between SPE and NSPE */
179     sau_and_idau_cfg();
180     if (bus_filter_cfg() != TFM_PLAT_ERR_SUCCESS) {
181         return TFM_HAL_ERROR_GENERIC;
182     }
183 
184     if (dma_security_config() != TFM_PLAT_ERR_SUCCESS) {
185         return TFM_HAL_ERROR_GENERIC;
186     }
187 
188     /* Set up static isolation boundaries inside SPE */
189 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
190     int32_t i;
191 
192     uint32_t mpu_region_num =
193         (MPU ->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
194 
195     if (mpu_region_num < ARRAY_SIZE(mpu_region_attributes)) {
196         return TFM_HAL_ERROR_GENERIC;
197     }
198 
199     /* Turn off MPU during configuration */
200     if ((MPU->CTRL & MPU_CTRL_ENABLE_Msk)) {
201         ARM_MPU_Disable();
202     }
203     /* Disable all regions */
204     for (i = 0; i < mpu_region_num; i++) {
205         ARM_MPU_ClrRegion(i);
206     }
207 
208     /* Configure attribute registers
209      * Attr0 : Normal memory, Inner/Outer Cacheable, Write-Trough Read-Allocate
210      */
211     ARM_MPU_SetMemAttr(0,
212                    ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
213                                                      ARM_MPU_WRITE_THROUGH,
214                                                      ARM_MPU_READ_ALLOCATE,
215                                                      ARM_MPU_NON_WRITE_ALLOCATE),
216                                 ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
217                                                      ARM_MPU_WRITE_THROUGH,
218                                                      ARM_MPU_READ_ALLOCATE,
219                                                      ARM_MPU_NON_WRITE_ALLOCATE)));
220     /* Attr1 : Normal memory, Inner/Outer Cacheable, Write-Back R-W Allocate */
221     ARM_MPU_SetMemAttr(1,
222                     ARM_MPU_ATTR(ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
223                                                      ARM_MPU_WRITE_BACK,
224                                                      ARM_MPU_READ_ALLOCATE,
225                                                      ARM_MPU_WRITE_ALLOCATE),
226                                 ARM_MPU_ATTR_MEMORY_(ARM_MPU_NON_TRANSIENT,
227                                                      ARM_MPU_WRITE_BACK,
228                                                      ARM_MPU_READ_ALLOCATE,
229                                                      ARM_MPU_WRITE_ALLOCATE)));
230     /* Attr2 : Device memory, nGnRE */
231     ARM_MPU_SetMemAttr(2,
232                        ARM_MPU_ATTR(ARM_MPU_ATTR_DEVICE,
233                                     ARM_MPU_ATTR_DEVICE_nGnRE));
234 
235     /* Configure regions */
236     /* Note: CMSIS MPU API clears the lower 5 address bits without check */
237     for (i = 0; i < ARRAY_SIZE(mpu_region_attributes); i++) {
238         localcfg.RBAR = mpu_region_attributes[i].RBAR;
239         localcfg.RLAR = mpu_region_attributes[i].RLAR;
240         ARM_MPU_SetRegion(i, localcfg.RBAR, localcfg.RLAR);
241     }
242     n_configured_regions = i;
243 
244     /* Enable MPU with the above configurations. Allow default memory map for
245      * privileged software and enable MPU during HardFault and NMI handlers.
246      */
247     ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
248 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
249 
250     *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
251 
252     return TFM_HAL_SUCCESS;
253 }
254 
255 /*
256  * Implementation of tfm_hal_bind_boundary():
257  *
258  * The API encodes some attributes into a handle and returns it to SPM.
259  * The attributes include isolation boundaries, privilege, and MMIO information.
260  * When scheduler switches running partitions, SPM compares the handle between
261  * partitions to know if boundary update is necessary. If update is required,
262  * SPM passes the handle to platform to do platform settings and update
263  * isolation boundaries.
264  */
tfm_hal_bind_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t * p_boundary)265 enum tfm_hal_status_t tfm_hal_bind_boundary(
266                                     const struct partition_load_info_t *p_ldinf,
267                                     uintptr_t *p_boundary)
268 {
269     uint32_t i, j;
270     bool privileged;
271     bool ns_agent_tz;
272     uint32_t partition_attrs = 0;
273     const struct asset_desc_t *p_asset;
274     struct platform_data_t *plat_data_ptr;
275     const uintptr_t* mmio_list;
276     size_t mmio_list_length;
277 
278 #if TFM_ISOLATION_LEVEL == 2
279     ARM_MPU_Region_t local_mpu_region;
280     uint32_t mpu_region_num;
281 #endif
282     if (!p_ldinf || !p_boundary) {
283         return TFM_HAL_ERROR_GENERIC;
284     }
285 
286 #if TFM_ISOLATION_LEVEL == 1
287     privileged = true;
288 #else
289     privileged = IS_PSA_ROT(p_ldinf);
290 #endif
291 
292     ns_agent_tz = IS_NS_AGENT_TZ(p_ldinf);
293     p_asset = LOAD_INFO_ASSET(p_ldinf);
294 
295     get_partition_named_mmio_list(&mmio_list, &mmio_list_length);
296 
297     /*
298      * Validate if the named MMIO of partition is allowed by the platform.
299      * Otherwise, skip validation.
300      *
301      * NOTE: Need to add validation of numbered MMIO if platform requires.
302      */
303     for (i = 0; i < p_ldinf->nassets; i++) {
304         if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
305             continue;
306         }
307         for (j = 0; j < mmio_list_length; j++) {
308             if (p_asset[i].dev.dev_ref == mmio_list[j]) {
309                 break;
310             }
311         }
312 
313         if (j == mmio_list_length) {
314             /* The MMIO asset is not in the allowed list of platform. */
315             return TFM_HAL_ERROR_GENERIC;
316         }
317         /* Assume sec and priv settings are required even under level 1 */
318         plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
319                                          struct platform_data_t *);
320 
321         if (plat_data_ptr->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
322             if (privileged) {
323                 access_ctrl_configure_to_secure_privileged(
324                     (access_ctrl_reg_offset)plat_data_ptr->periph_ppc_mask);
325             } else {
326                 access_ctrl_configure_to_secure_unprivileged(
327                     (access_ctrl_reg_offset)plat_data_ptr->periph_ppc_mask);
328             }
329         }
330 #if TFM_ISOLATION_LEVEL == 2
331         /*
332          * Static boundaries are set. Set up MPU region for MMIO.
333          * Setup regions for unprivileged assets only.
334          */
335         if (!privileged) {
336             mpu_region_num =
337                 (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
338 
339             /* There is a limited number of available MPU regions in v8M */
340             if (mpu_region_num <= n_configured_regions) {
341                 return TFM_HAL_ERROR_GENERIC;
342             }
343             if ((plat_data_ptr->periph_start & ~MPU_RBAR_BASE_Msk) != 0) {
344                 return TFM_HAL_ERROR_GENERIC;
345             }
346             if ((plat_data_ptr->periph_limit & ~MPU_RLAR_LIMIT_Msk) != 0x1F) {
347                 return TFM_HAL_ERROR_GENERIC;
348             }
349 
350             /* Turn off MPU during configuration */
351             if (MPU->CTRL & MPU_CTRL_ENABLE_Msk) {
352                 ARM_MPU_Disable();
353             }
354 
355             /* Assemble region base and limit address register contents. */
356             local_mpu_region.RBAR = ARM_MPU_RBAR(plat_data_ptr->periph_start,
357                                                  ARM_MPU_SH_NON,
358                                                  ARM_MPU_READ_WRITE,
359                                                  ARM_MPU_UNPRIVILEGED,
360                                                  ARM_MPU_EXECUTE_NEVER);
361             /* Attr2 contains required attribute set for device regions */
362             #ifdef TFM_PXN_ENABLE
363             local_mpu_region.RLAR = ARM_MPU_RLAR_PXN(plat_data_ptr->periph_limit,
364                                                      ARM_MPU_PRIVILEGE_EXECUTE_NEVER,
365                                                      2);
366             #else
367             local_mpu_region.RLAR = ARM_MPU_RLAR(plat_data_ptr->periph_limit,
368                                                  2);
369             #endif
370 
371             /* Configure device mpu region */
372             ARM_MPU_SetRegion(n_configured_regions,
373                               local_mpu_region.RBAR,
374                               local_mpu_region.RLAR);
375 
376             n_configured_regions++;
377 
378             /* Enable MPU with the new region added */
379             ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
380         }
381 #endif
382     }
383 
384     partition_attrs = ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
385                         HANDLE_ATTR_PRIV_MASK;
386     partition_attrs |= ((uint32_t)ns_agent_tz << HANDLE_ATTR_NS_POS) &
387                         HANDLE_ATTR_NS_MASK;
388     *p_boundary = (uintptr_t)partition_attrs;
389 
390     return TFM_HAL_SUCCESS;
391 }
392 
tfm_hal_activate_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t boundary)393 enum tfm_hal_status_t tfm_hal_activate_boundary(
394                              const struct partition_load_info_t *p_ldinf,
395                              uintptr_t boundary)
396 {
397     CONTROL_Type ctrl;
398     bool privileged = !!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK);
399 
400     /* Privileged level is required to be set always */
401     ctrl.w = __get_CONTROL();
402     ctrl.b.nPRIV = privileged ? 0 : 1;
403     __set_CONTROL(ctrl.w);
404 
405     return TFM_HAL_SUCCESS;
406 }
407 
tfm_hal_memory_check(uintptr_t boundary,uintptr_t base,size_t size,uint32_t access_type)408 enum tfm_hal_status_t tfm_hal_memory_check(uintptr_t boundary, uintptr_t base,
409                                            size_t size, uint32_t access_type)
410 {
411     int flags = 0;
412 
413     /* If size is zero, this indicates an empty buffer and base is ignored */
414     if (size == 0) {
415         return TFM_HAL_SUCCESS;
416     }
417 
418     if (!base) {
419         return TFM_HAL_ERROR_INVALID_INPUT;
420     }
421 
422     if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
423         flags |= CMSE_MPU_READWRITE;
424     } else if (access_type & TFM_HAL_ACCESS_READABLE) {
425         flags |= CMSE_MPU_READ;
426     } else {
427         return TFM_HAL_ERROR_INVALID_INPUT;
428     }
429 
430     if (access_type & TFM_HAL_ACCESS_NS) {
431         flags |= CMSE_NONSECURE;
432     }
433 
434     if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
435         flags |= CMSE_MPU_UNPRIV;
436     }
437 
438     /* This check is only done for ns_agent_tz */
439     if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
440         CONTROL_Type ctrl;
441         ctrl.w = __TZ_get_CONTROL_NS();
442         if (ctrl.b.nPRIV == 1) {
443             flags |= CMSE_MPU_UNPRIV;
444         } else {
445             flags &= ~CMSE_MPU_UNPRIV;
446         }
447         flags |= CMSE_NONSECURE;
448     }
449 
450     if (cmse_check_address_range((void *)base, size, flags) != NULL) {
451         return TFM_HAL_SUCCESS;
452     } else {
453         return TFM_HAL_ERROR_MEM_FAULT;
454     }
455 }
456 
tfm_hal_boundary_need_switch(uintptr_t boundary_from,uintptr_t boundary_to)457 bool tfm_hal_boundary_need_switch(uintptr_t boundary_from,
458                                   uintptr_t boundary_to)
459 {
460     if (boundary_from == boundary_to) {
461         return false;
462     }
463 
464     if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
465         ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
466         return false;
467     }
468     return true;
469 }
470