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