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 <string.h>
15 #include "array.h"
16 #include "cmsis.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_plat_defs.h"
25 #include "region_defs.h"
26 #include "tfm_peripherals_def.h"
27 #include "load/partition_defs.h"
28 #include "load/asset_defs.h"
29 #include "load/spm_load_api.h"
30 #include "low_level_rng.h"
31 #include "boot_hal_cfg.h"
32 
33 #ifdef FLOW_CONTROL
34 #include "target_flowcontrol.h"
35 #else
36 /* dummy definitions */
37 extern volatile uint32_t uFlowStage;
38 #define FLOW_CONTROL_STEP(C,B,A) ((void)0)
39 #define FLOW_CONTROL_CHECK(B,A) ((void)0)
40 #define FLOW_STAGE_CFG          (0x0)
41 #define FLOW_STAGE_CHK          (0x1)
42 #endif
43 
44 /* It can be retrieved from the MPU_TYPE register. */
45 #define MPU_REGION_NUM                  8
46 #define PROT_BOUNDARY_VAL \
47     ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
48 
49 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
50 static uint32_t n_configured_regions = 0;
51 
52 struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
53 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
54 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
55 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
56 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
57 
58 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_START, $$Base);
59 REGION_DECLARE(Image$$, TFM_APP_RW_STACK_END, $$Base);
60 
61 REGION_DECLARE(Image$$, ER_VENEER, $$Limit);
62 
63 const struct mpu_armv8m_region_cfg_t region_cfg[] = {
64     /* TFM Core unprivileged code region */
65     {
66         0, /* will be updated before using */
67         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
68         FLASH_BASE_S + FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE - 32,
69         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
70         MPU_ARMV8M_XN_EXEC_OK,
71         MPU_ARMV8M_AP_RO_PRIV_UNPRIV,
72         MPU_ARMV8M_SH_NONE,
73 #ifdef FLOW_CONTROL
74         FLOW_STEP_MPU_S_EN_R0,
75         FLOW_CTRL_MPU_S_EN_R0,
76         FLOW_STEP_MPU_S_CH_R0,
77         FLOW_CTRL_MPU_S_CH_R0,
78 #endif /* FLOW_CONTROL */
79     },
80     /* TFM_Core privileged code region   */
81     {
82         0, /* will be updated before using */
83         S_CODE_START,
84         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base),
85         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
86         MPU_ARMV8M_XN_EXEC_OK,
87         MPU_ARMV8M_AP_RO_PRIV_ONLY,
88         MPU_ARMV8M_SH_NONE,
89 #ifdef FLOW_CONTROL
90         FLOW_STEP_MPU_S_EN_R2,
91         FLOW_CTRL_MPU_S_EN_R2,
92         FLOW_STEP_MPU_S_CH_R2,
93         FLOW_CTRL_MPU_S_CH_R2,
94 #endif /* FLOW_CONTROL */
95     },
96     {
97       0, /* will be updated before using */
98         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
99         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base),
100         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
101         MPU_ARMV8M_XN_EXEC_NEVER,
102         MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
103         MPU_ARMV8M_SH_NONE,
104 #ifdef FLOW_CONTROL
105         FLOW_STEP_MPU_S_EN_R1,
106         FLOW_CTRL_MPU_S_EN_R1,
107         FLOW_STEP_MPU_S_CH_R1,
108         FLOW_CTRL_MPU_S_CH_R1,
109 #endif /* FLOW_CONTROL */
110     },
111     /* TFM_Core privileged data region   */
112     {
113         0, /* will be updated before using */
114         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base),
115         S_DATA_LIMIT + 1,
116         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
117         MPU_ARMV8M_XN_EXEC_NEVER,
118         MPU_ARMV8M_AP_RW_PRIV_ONLY,
119         MPU_ARMV8M_SH_NONE,
120 #ifdef FLOW_CONTROL
121         FLOW_STEP_MPU_S_EN_R3,
122         FLOW_CTRL_MPU_S_EN_R3,
123         FLOW_STEP_MPU_S_CH_R3,
124         FLOW_CTRL_MPU_S_CH_R3,
125 #endif /* FLOW_CONTROL */
126     },
127     /* peripheral for AppROT partition */
128     {
129         0, /* will be updated before using */
130         PERIPH_BASE_S,
131         PERIPH_BASE_S+0x10000000,
132         MPU_ARMV8M_MAIR_ATTR_DATANOCACHE_IDX,
133         MPU_ARMV8M_XN_EXEC_NEVER,
134         MPU_ARMV8M_AP_RW_PRIV_UNPRIV,
135         MPU_ARMV8M_SH_NONE,
136 #ifdef FLOW_CONTROL
137         FLOW_STEP_MPU_S_EN_R4,
138         FLOW_CTRL_MPU_S_EN_R4,
139         FLOW_STEP_MPU_S_CH_R4,
140         FLOW_CTRL_MPU_S_CH_R4,
141 #endif /* FLOW_CONTROL */
142     },
143     /* TFM Non volatile data region (OTP/NVM/SST/ITS) */
144     /* OTP is write protected (Option Byte protection) */
145     {
146         0, /* will be updated before using */
147         TFM_NV_DATA_START,
148         TFM_NV_DATA_LIMIT + 1,
149         MPU_ARMV8M_MAIR_ATTR_DATANOCACHE_IDX,
150         MPU_ARMV8M_XN_EXEC_NEVER,
151         MPU_ARMV8M_AP_RW_PRIV_ONLY,
152         MPU_ARMV8M_SH_NONE,
153 #ifdef FLOW_CONTROL
154         FLOW_STEP_MPU_S_EN_R5,
155         FLOW_CTRL_MPU_S_EN_R5,
156         FLOW_STEP_MPU_S_CH_R5,
157         FLOW_CTRL_MPU_S_CH_R5,
158 #endif /* FLOW_CONTROL */
159     },
160     /* RAM Non Secure Alias Not Executable */
161     {
162         0, /* will be updated before using */
163         SRAM1_BASE_NS,
164         SRAM4_BASE_NS + SRAM4_SIZE,
165         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
166         MPU_ARMV8M_XN_EXEC_NEVER,
167         MPU_ARMV8M_AP_RW_PRIV_ONLY,
168         MPU_ARMV8M_SH_NONE,
169 #ifdef FLOW_CONTROL
170         FLOW_STEP_MPU_S_EN_R6,
171         FLOW_CTRL_MPU_S_EN_R6,
172         FLOW_STEP_MPU_S_CH_R6,
173         FLOW_CTRL_MPU_S_CH_R6,
174 #endif /* FLOW_CONTROL */
175     },
176     /* FLASH Non Secure Alias Not Executable, read only */
177     {
178         0, /* will be updated before using */
179         FLASH_BASE_NS,
180         FLASH_BASE_NS + FLASH_AREA_1_OFFSET + FLASH_AREA_1_SIZE - 32,
181         MPU_ARMV8M_MAIR_ATTR_DATANOCACHE_IDX,
182         MPU_ARMV8M_XN_EXEC_NEVER,
183         MPU_ARMV8M_AP_RO_PRIV_ONLY,
184         MPU_ARMV8M_SH_NONE,
185 #ifdef FLOW_CONTROL
186         FLOW_STEP_MPU_S_EN_R7,
187         FLOW_CTRL_MPU_S_EN_R7,
188         FLOW_STEP_MPU_S_CH_R7,
189         FLOW_CTRL_MPU_S_CH_R7,
190 #endif /* FLOW_CONTROL */
191     },
192 };
193 
mpu_init(void)194 static enum tfm_hal_status_t mpu_init(void)
195 {
196     uint32_t i;
197     struct mpu_armv8m_region_cfg_t localcfg;
198 
199     /* configuration stage */
200     if (uFlowStage == FLOW_STAGE_CFG)
201     {
202         mpu_armv8m_clean(&dev_mpu_s);
203 
204         /* configure secure MPU regions */
205         for (i = 0; i < ARRAY_SIZE(region_cfg); i++)
206         {
207             memcpy(&localcfg, &region_cfg[i], sizeof(localcfg));
208             localcfg.region_nr = i;
209 
210             if (mpu_armv8m_region_enable(&dev_mpu_s,
211                         &localcfg) != MPU_ARMV8M_OK)
212             {
213                 return TFM_HAL_ERROR_GENERIC;
214             }
215             else
216             {
217                 /* Execution stopped if flow control failed */
218                 FLOW_CONTROL_STEP(uFlowProtectValue, localcfg.flow_step_enable,
219                         region_cfg[i].flow_ctrl_enable);
220             }
221         }
222         n_configured_regions = i;
223 
224         /* enable secure MPU */
225         mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
226         FLOW_CONTROL_STEP(uFlowProtectValue, FLOW_STEP_MPU_S_EN, FLOW_CTRL_MPU_S_EN);
227     }
228     /* verification stage */
229     else
230     {
231         /* check secure MPU regions */
232         for (i = 0; i < ARRAY_SIZE(region_cfg); i++)
233         {
234             memcpy(&localcfg, &region_cfg[i], sizeof(localcfg));
235             localcfg.region_nr = i;
236 
237             if (mpu_armv8m_region_enable_check(&dev_mpu_s,
238                         &localcfg) != MPU_ARMV8M_OK)
239             {
240                 Error_Handler();
241             }
242             else
243             {
244                 /* Execution stopped if flow control failed */
245                 FLOW_CONTROL_STEP(uFlowProtectValue, localcfg.flow_step_check,
246                         region_cfg[i].flow_ctrl_check);
247             }
248         }
249 
250         /* check secure MPU */
251         if (mpu_armv8m_check(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
252                     HARDFAULT_NMI_ENABLE) != MPU_ARMV8M_OK)
253         {
254             Error_Handler();
255         }
256         else
257         {
258             /* Execution stopped if flow control failed */
259             FLOW_CONTROL_STEP(uFlowProtectValue, FLOW_STEP_MPU_S_CH, FLOW_CTRL_MPU_S_CH);
260         }
261 
262         /* Lock MPU config */
263         __HAL_RCC_SYSCFG_CLK_ENABLE();
264         /* in TFM_DEV_MODE MPU is not locked, this allows to see MPU configuration */
265 #ifndef TFM_DEV_MODE
266         SYSCFG->CSLCKR |= SYSCFG_CSLCKR_LOCKSMPU;
267 #endif
268         FLOW_CONTROL_STEP(uFlowProtectValue, FLOW_STEP_MPU_S_LCK, FLOW_CTRL_MPU_S_LCK);
269 #ifndef TFM_DEV_MODE
270         if (!(SYSCFG->CSLCKR & SYSCFG_CSLCKR_LOCKSMPU))
271             Error_Handler();
272 #endif
273         FLOW_CONTROL_STEP(uFlowProtectValue, FLOW_STEP_MPU_S_LCK_CH, FLOW_CTRL_MPU_S_LCK_CH);
274     }
275 
276     return TFM_HAL_SUCCESS;
277 }
278 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
279 
tfm_hal_set_up_static_boundaries(uintptr_t * p_spm_boundary)280 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_set_up_static_boundaries(
281                                             uintptr_t *p_spm_boundary)
282 {
283     /* Set up isolation boundaries between SPE and NSPE */
284     /* Configures non-secure memory spaces in the target */
285     uFlowStage = FLOW_STAGE_CFG;
286     gtzc_init_cfg();
287     sau_and_idau_cfg();
288     pinmux_init_cfg();
289 
290     /* Check configurations with Flow control to resist to basic HW attacks */
291     uFlowStage = FLOW_STAGE_CHK;
292     gtzc_init_cfg();
293     sau_and_idau_cfg();
294 
295     /* Start HW randomization */
296     if (RNG_Init()){
297         Error_Handler();
298     };
299 
300 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
301     uFlowStage = FLOW_STAGE_CFG;
302     mpu_init();
303     uFlowStage = FLOW_STAGE_CHK;
304     mpu_init();
305 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
306 
307     *p_spm_boundary = (uintptr_t)PROT_BOUNDARY_VAL;
308 
309     FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
310 }
311 
312 #ifdef TFM_FIH_PROFILE_ON
tfm_hal_verify_static_boundaries(void)313 fih_int tfm_hal_verify_static_boundaries(void)
314 {
315     FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
316 }
317 #endif
318 
319 /*
320  * Implementation of tfm_hal_bind_boundary() on STM:
321  *
322  * The API encodes some attributes into a handle and returns it to SPM.
323  * The attributes include isolation boundaries, privilege, and MMIO information.
324  * When scheduler switches running partitions, SPM compares the handle between
325  * partitions to know if boundary update is necessary. If update is required,
326  * SPM passes the handle to platform to do platform settings and update
327  * isolation boundaries.
328  *
329  * The handle should be unique under isolation level 3. The implementation
330  * encodes an index at the highest 8 bits to assure handle uniqueness. While
331  * under isolation level 1/2, handles may not be unique.
332  *
333  * The encoding format assignment:
334  * - For isolation level 3
335  *      BIT | 31        24 | 23         20 | ... | 7           4 | 3       0 |
336  *          | Unique Index | Region Attr 5 | ... | Region Attr 1 | Base Attr |
337  *
338  *      In which the "Region Attr i" is:
339  *      BIT |       3      | 2        0 |
340  *          | 1: RW, 0: RO | MMIO Index |
341  *
342  *      In which the "Base Attr" is:
343  *      BIT |               1                |                           0                     |
344  *          | 1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
345  *
346  * - For isolation level 1/2
347  *      BIT | 31     2 |              1                |                           0                     |
348  *          | Reserved |1: privileged, 0: unprivileged | 1: Trustzone-specific NSPE, 0: Secure partition |
349  *
350  * This is a reference implementation on STM, and may have some limitations.
351  * 1. The maximum number of allowed MMIO regions is 5.
352  * 2. Highest 8 bits are for index. It supports 256 unique handles at most.
353  */
354 
tfm_hal_bind_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t * p_boundary)355 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_bind_boundary(
356                                     const struct partition_load_info_t *p_ldinf,
357                                     uintptr_t *p_boundary)
358 {
359     uint32_t i, j;
360     bool privileged;
361     bool ns_agent;
362     uint32_t partition_attrs = 0;
363     const struct asset_desc_t *p_asset;
364     struct platform_data_t *plat_data_ptr;
365 #if TFM_ISOLATION_LEVEL == 2
366     struct mpu_armv8m_region_cfg_t localcfg;
367 #endif
368 
369     if (!p_ldinf || !p_boundary) {
370         FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
371     }
372 
373 #if TFM_ISOLATION_LEVEL == 1
374     privileged = true;
375 #else
376     privileged = IS_PSA_ROT(p_ldinf);
377 #endif
378 
379     ns_agent = IS_NS_AGENT(p_ldinf);
380     p_asset = LOAD_INFO_ASSET(p_ldinf);
381 
382     /*
383      * Validate if the named MMIO of partition is allowed by the platform.
384      * Otherwise, skip validation.
385      *
386      * NOTE: Need to add validation of numbered MMIO if platform requires.
387      */
388     for (i = 0; i < p_ldinf->nassets; i++) {
389         if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
390             continue;
391         }
392         for (j = 0; j < ARRAY_SIZE(partition_named_mmio_list); j++) {
393             if (p_asset[i].dev.dev_ref == partition_named_mmio_list[j]) {
394                 break;
395             }
396         }
397 
398         if (j == ARRAY_SIZE(partition_named_mmio_list)) {
399             /* The MMIO asset is not in the allowed list of platform. */
400             FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
401         }
402 #if TFM_ISOLATION_LEVEL == 2
403         plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
404                                          struct platform_data_t *);
405         /*
406          * Static boundaries are set. Set up MPU region for MMIO.
407          * Setup regions for unprivileged assets only.
408          */
409         if (!privileged) {
410             localcfg.region_base = plat_data_ptr->periph_start;
411             localcfg.region_limit = plat_data_ptr->periph_limit;
412             localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
413             localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
414             localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
415             localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
416             localcfg.region_nr = n_configured_regions++;
417 
418             if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg)
419                 != MPU_ARMV8M_OK) {
420                 FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
421             }
422         }
423 #endif
424     }
425     partition_attrs = ((uint32_t)privileged << HANDLE_ATTR_PRIV_POS) &
426                         HANDLE_ATTR_PRIV_MASK;
427     partition_attrs |= ((uint32_t)ns_agent << HANDLE_ATTR_NS_POS) &
428                         HANDLE_ATTR_NS_MASK;
429     *p_boundary = (uintptr_t)partition_attrs;
430 
431     FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
432 }
433 
tfm_hal_activate_boundary(const struct partition_load_info_t * p_ldinf,uintptr_t boundary)434 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_activate_boundary(
435                              const struct partition_load_info_t *p_ldinf,
436                              uintptr_t boundary)
437 {
438     CONTROL_Type ctrl;
439     uint32_t local_handle = (uint32_t)boundary;
440     bool privileged = !!(local_handle & HANDLE_ATTR_PRIV_MASK);
441 
442     /* Privileged level is required to be set always */
443     ctrl.w = __get_CONTROL();
444     ctrl.b.nPRIV = privileged ? 0 : 1;
445     __set_CONTROL(ctrl.w);
446 
447     FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
448 }
449 
tfm_hal_memory_check(uintptr_t boundary,uintptr_t base,size_t size,uint32_t access_type)450 FIH_RET_TYPE(enum tfm_hal_status_t) tfm_hal_memory_check(uintptr_t boundary, uintptr_t base,
451                                            size_t size, uint32_t access_type)
452 {
453     int flags = 0;
454 
455     /* If size is zero, this indicates an empty buffer and base is ignored */
456     if (size == 0) {
457         FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
458     }
459 
460     if (!base) {
461         FIH_RET(fih_int_encode(TFM_HAL_ERROR_INVALID_INPUT));
462     }
463 
464     if ((access_type & TFM_HAL_ACCESS_READWRITE) == TFM_HAL_ACCESS_READWRITE) {
465         flags |= CMSE_MPU_READWRITE;
466     } else if (access_type & TFM_HAL_ACCESS_READABLE) {
467         flags |= CMSE_MPU_READ;
468     } else {
469         FIH_RET(fih_int_encode(TFM_HAL_ERROR_INVALID_INPUT));
470     }
471 
472     if (!((uint32_t)boundary & HANDLE_ATTR_PRIV_MASK)) {
473         flags |= CMSE_MPU_UNPRIV;
474     }
475 
476     if ((uint32_t)boundary & HANDLE_ATTR_NS_MASK) {
477         CONTROL_Type ctrl;
478         ctrl.w = __TZ_get_CONTROL_NS();
479         if (ctrl.b.nPRIV == 1) {
480             flags |= CMSE_MPU_UNPRIV;
481         } else {
482             flags &= ~CMSE_MPU_UNPRIV;
483         }
484         flags |= CMSE_NONSECURE;
485     }
486 
487     if (cmse_check_address_range((void *)base, size, flags) != NULL) {
488         FIH_RET(fih_int_encode(TFM_HAL_SUCCESS));
489     } else {
490         FIH_RET(fih_int_encode(TFM_HAL_ERROR_MEM_FAULT));
491     }
492 }
493 
tfm_hal_boundary_need_switch(uintptr_t boundary_from,uintptr_t boundary_to)494 bool tfm_hal_boundary_need_switch(uintptr_t boundary_from,
495                                   uintptr_t boundary_to)
496 {
497     if (boundary_from == boundary_to) {
498         return false;
499     }
500 
501     if (((uint32_t)boundary_from & HANDLE_ATTR_PRIV_MASK) &&
502         ((uint32_t)boundary_to & HANDLE_ATTR_PRIV_MASK)) {
503         return false;
504     }
505     return true;
506 }
507