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)®ION_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)®ION_NAME(Image$$, VENEER_ALIGN, $$Limit) - 1,
84 ARM_MPU_PRIVILEGE_EXECUTE_OK,
85 0)
86 #else
87 ARM_MPU_RLAR((uint32_t)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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)®ION_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