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)®ION_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)®ION_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)®ION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
99 (uint32_t)®ION_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)®ION_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, ®ion_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, ®ion_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