1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2023, STMicroelectronics
4 */
5
6 #include <assert.h>
7 #include <config.h>
8 #include <drivers/rstctrl.h>
9 #include <drivers/stm32_remoteproc.h>
10 #ifdef CFG_STM32MP15
11 #include <drivers/stm32mp1_rcc.h>
12 #endif
13 #include <kernel/cache_helpers.h>
14 #include <kernel/dt_driver.h>
15 #include <kernel/tee_misc.h>
16 #include <libfdt.h>
17 #include <mm/core_memprot.h>
18 #include <mm/core_mmu.h>
19 #include <stm32_util.h>
20
21 #define TIMEOUT_US_1MS U(1000)
22
23 /**
24 * struct stm32_rproc_mem - Memory regions used by the remote processor
25 *
26 * @addr: physical base address from the CPU space perspective
27 * @da: device address corresponding to the physical base address
28 * from remote processor space perspective
29 * @size: size of the region
30 */
31 struct stm32_rproc_mem {
32 paddr_t addr;
33 paddr_t da;
34 size_t size;
35 };
36
37 /**
38 * struct stm32_rproc_instance - rproc instance context
39 *
40 * @cdata: pointer to the device compatible data
41 * @link: the node in the rproc_list
42 * @n_regions: number of memory regions
43 * @regions: memory regions used
44 * @mcu_rst: remote processor reset control
45 * @hold_boot: remote processor hold boot control
46 */
47 struct stm32_rproc_instance {
48 const struct stm32_rproc_compat_data *cdata;
49 SLIST_ENTRY(stm32_rproc_instance) link;
50 size_t n_regions;
51 struct stm32_rproc_mem *regions;
52 struct rstctrl *mcu_rst;
53 struct rstctrl *hold_boot;
54 };
55
56 /**
57 * struct stm32_rproc_compat_data - rproc associated data for compatible list
58 *
59 * @rproc_id: identifies the remote processor
60 * @ns_loading: True if supports non-secure firmware loading, false otherwise
61 */
62 struct stm32_rproc_compat_data {
63 uint32_t rproc_id;
64 bool ns_loading;
65 };
66
67 static SLIST_HEAD(, stm32_rproc_instance) rproc_list =
68 SLIST_HEAD_INITIALIZER(rproc_list);
69
stm32_rproc_get(uint32_t rproc_id)70 void *stm32_rproc_get(uint32_t rproc_id)
71 {
72 struct stm32_rproc_instance *rproc = NULL;
73
74 SLIST_FOREACH(rproc, &rproc_list, link)
75 if (rproc->cdata->rproc_id == rproc_id)
76 break;
77
78 return rproc;
79 }
80
stm32_rproc_is_secure(uint32_t rproc_id)81 bool stm32_rproc_is_secure(uint32_t rproc_id)
82 {
83 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
84
85 if (rproc)
86 return !rproc->cdata->ns_loading;
87
88 return false;
89 }
90
stm32_rproc_start(uint32_t rproc_id)91 TEE_Result stm32_rproc_start(uint32_t rproc_id)
92 {
93 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
94 TEE_Result res = TEE_ERROR_GENERIC;
95
96 if (!rproc || !rproc->hold_boot)
97 return TEE_ERROR_GENERIC;
98
99 /*
100 * The firmware is started by de-asserting the hold boot and
101 * asserting it back to avoid auto restart on a crash.
102 * No need to release the MCU reset as it is automatically released by
103 * the hardware.
104 */
105 res = rstctrl_deassert_to(rproc->hold_boot, TIMEOUT_US_1MS);
106 if (!res)
107 res = rstctrl_assert_to(rproc->hold_boot, TIMEOUT_US_1MS);
108
109 return res;
110 }
111
rproc_stop(struct stm32_rproc_instance * rproc)112 static TEE_Result rproc_stop(struct stm32_rproc_instance *rproc)
113 {
114 TEE_Result res = TEE_ERROR_GENERIC;
115
116 if (!rproc->hold_boot || !rproc->mcu_rst)
117 return TEE_ERROR_GENERIC;
118
119 res = rstctrl_assert_to(rproc->hold_boot, TIMEOUT_US_1MS);
120 if (!res)
121 res = rstctrl_assert_to(rproc->mcu_rst, TIMEOUT_US_1MS);
122
123 return res;
124 }
125
stm32_rproc_stop(uint32_t rproc_id)126 TEE_Result stm32_rproc_stop(uint32_t rproc_id)
127 {
128 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
129
130 if (!rproc)
131 return TEE_ERROR_BAD_PARAMETERS;
132
133 return rproc_stop(rproc);
134 }
135
stm32_rproc_da_to_pa(uint32_t rproc_id,paddr_t da,size_t size,paddr_t * pa)136 TEE_Result stm32_rproc_da_to_pa(uint32_t rproc_id, paddr_t da, size_t size,
137 paddr_t *pa)
138 {
139 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
140 struct stm32_rproc_mem *mems = NULL;
141 unsigned int i = 0;
142
143 if (!rproc)
144 return TEE_ERROR_BAD_PARAMETERS;
145
146 mems = rproc->regions;
147
148 for (i = 0; i < rproc->n_regions; i++) {
149 if (core_is_buffer_inside(da, size, mems[i].da, mems[i].size)) {
150 /*
151 * A match between the requested DA memory area and the
152 * registered regions has been found.
153 * The PA is the reserved-memory PA address plus the
154 * delta between the requested DA and the
155 * reserved-memory DA address.
156 */
157 *pa = mems[i].addr + da - mems[i].da;
158 return TEE_SUCCESS;
159 }
160 }
161
162 return TEE_ERROR_ACCESS_DENIED;
163 }
164
stm32_rproc_map(uint32_t rproc_id,paddr_t pa,size_t size,void ** va)165 TEE_Result stm32_rproc_map(uint32_t rproc_id, paddr_t pa, size_t size,
166 void **va)
167 {
168 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
169 struct stm32_rproc_mem *mems = NULL;
170 unsigned int i = 0;
171
172 if (!rproc)
173 return TEE_ERROR_BAD_PARAMETERS;
174
175 mems = rproc->regions;
176
177 for (i = 0; i < rproc->n_regions; i++) {
178 if (!core_is_buffer_inside(pa, size, mems[i].addr,
179 mems[i].size))
180 continue;
181 *va = core_mmu_add_mapping(MEM_AREA_RAM_NSEC, pa, size);
182 if (!*va) {
183 EMSG("Can't map region %#"PRIxPA" size %zu", pa, size);
184 return TEE_ERROR_GENERIC;
185 }
186
187 return TEE_SUCCESS;
188 }
189
190 return TEE_ERROR_ACCESS_DENIED;
191 }
192
stm32_rproc_unmap(uint32_t rproc_id,void * va,size_t size)193 TEE_Result stm32_rproc_unmap(uint32_t rproc_id, void *va, size_t size)
194 {
195 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
196 struct stm32_rproc_mem *mems = NULL;
197 paddr_t pa = virt_to_phys(va);
198 unsigned int i = 0;
199
200 if (!rproc || !pa)
201 return TEE_ERROR_BAD_PARAMETERS;
202
203 mems = rproc->regions;
204
205 for (i = 0; i < rproc->n_regions; i++) {
206 if (!core_is_buffer_inside(pa, size, mems[i].addr,
207 mems[i].size))
208 continue;
209
210 /* Flush the cache before unmapping the memory */
211 dcache_clean_range(va, size);
212
213 if (core_mmu_remove_mapping(MEM_AREA_RAM_NSEC, va, size)) {
214 EMSG("Can't unmap region %#"PRIxPA" size %zu",
215 pa, size);
216 return TEE_ERROR_GENERIC;
217 }
218
219 return TEE_SUCCESS;
220 }
221
222 return TEE_ERROR_ACCESS_DENIED;
223 }
224
stm32_rproc_get_dma_range(struct stm32_rproc_mem * region,const void * fdt,int node)225 static TEE_Result stm32_rproc_get_dma_range(struct stm32_rproc_mem *region,
226 const void *fdt, int node)
227 {
228 const fdt32_t *list = NULL;
229 int ahb_node = 0;
230 int len = 0;
231 int nranges = 0;
232 int i = 0;
233
234 /*
235 * The match between local and remote processor memory mapping is
236 * described in the dma-ranges defined by the bus parent node.
237 */
238 ahb_node = fdt_parent_offset(fdt, node);
239
240 list = fdt_getprop(fdt, ahb_node, "dma-ranges", &len);
241 if (!list) {
242 if (len != -FDT_ERR_NOTFOUND)
243 return TEE_ERROR_GENERIC;
244 /* Same memory mapping */
245 DMSG("No dma-ranges found in DT");
246 region->da = region->addr;
247 return TEE_SUCCESS;
248 }
249
250 if ((len % (sizeof(uint32_t) * 3)))
251 return TEE_ERROR_GENERIC;
252
253 nranges = len / sizeof(uint32_t);
254
255 for (i = 0; i < nranges; i += 3) {
256 uint32_t da = fdt32_to_cpu(list[i]);
257 uint32_t pa = fdt32_to_cpu(list[i + 1]);
258 uint32_t size = fdt32_to_cpu(list[i + 2]);
259
260 if (core_is_buffer_inside(region->addr, region->size,
261 pa, size)) {
262 region->da = da + (region->addr - pa);
263 return TEE_SUCCESS;
264 }
265 }
266
267 return TEE_ERROR_BAD_PARAMETERS;
268 }
269
270 /* Get device tree memory regions reserved for the Cortex-M and the IPC */
stm32_rproc_parse_mems(struct stm32_rproc_instance * rproc,const void * fdt,int node)271 static TEE_Result stm32_rproc_parse_mems(struct stm32_rproc_instance *rproc,
272 const void *fdt, int node)
273 {
274 const fdt32_t *list = NULL;
275 TEE_Result res = TEE_ERROR_GENERIC;
276 struct stm32_rproc_mem *regions = NULL;
277 int len = 0;
278 int n_regions = 0;
279 int i = 0;
280
281 list = fdt_getprop(fdt, node, "memory-region", &len);
282 if (!list) {
283 EMSG("No memory regions found in DT");
284 return TEE_ERROR_GENERIC;
285 }
286
287 n_regions = len / sizeof(uint32_t);
288
289 regions = calloc(n_regions, sizeof(*regions));
290 if (!regions)
291 return TEE_ERROR_OUT_OF_MEMORY;
292
293 for (i = 0; i < n_regions; i++) {
294 int pnode = 0;
295
296 pnode = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(list[i]));
297 if (pnode < 0) {
298 res = TEE_ERROR_GENERIC;
299 goto err;
300 }
301
302 if (fdt_reg_info(fdt, pnode, ®ions[i].addr,
303 ®ions[i].size)) {
304 res = TEE_ERROR_GENERIC;
305 goto err;
306 }
307
308 #if defined(CFG_STM32MP15)
309 if (stm32mp1_ram_intersect_pager_ram(regions[i].addr,
310 regions[i].size)) {
311 EMSG("Region %#"PRIxPA"..%#"PRIxPA" intersects pager secure memory",
312 regions[i].addr,
313 regions[i].addr + regions[i].size);
314 return TEE_ERROR_GENERIC;
315 }
316 #endif
317
318 res = stm32_rproc_get_dma_range(®ions[i], fdt, node);
319 if (res)
320 goto err;
321
322 if (!regions[i].addr || !regions[i].size) {
323 res = TEE_ERROR_BAD_PARAMETERS;
324 goto err;
325 }
326
327 DMSG("register region %#"PRIxPA" size %#zx",
328 regions[i].addr, regions[i].size);
329 }
330
331 rproc->n_regions = n_regions;
332 rproc->regions = regions;
333
334 return TEE_SUCCESS;
335
336 err:
337 free(regions);
338
339 return res;
340 }
341
stm32_rproc_clean_up_memories(uint32_t rproc_id)342 TEE_Result stm32_rproc_clean_up_memories(uint32_t rproc_id)
343 {
344 struct stm32_rproc_instance *rproc = stm32_rproc_get(rproc_id);
345 struct stm32_rproc_mem *mems = NULL;
346 TEE_Result res = TEE_ERROR_GENERIC;
347 unsigned int i = 0;
348 void *va = NULL;
349 size_t size = 0;
350 paddr_t pa = 0;
351
352 if (!rproc)
353 return TEE_ERROR_BAD_PARAMETERS;
354
355 mems = rproc->regions;
356 for (i = 0; i < rproc->n_regions; i++) {
357 pa = mems[i].addr;
358 size = mems[i].size;
359 res = stm32_rproc_map(rproc_id, pa, size, &va);
360 if (res)
361 break;
362 memset(va, 0, size);
363 res = stm32_rproc_unmap(rproc_id, va, size);
364 if (res)
365 break;
366 }
367
368 return res;
369 }
370
stm32_rproc_cleanup(struct stm32_rproc_instance * rproc)371 static void stm32_rproc_cleanup(struct stm32_rproc_instance *rproc)
372 {
373 free(rproc->regions);
374 free(rproc);
375 }
376
stm32_rproc_probe(const void * fdt,int node,const void * comp_data)377 static TEE_Result stm32_rproc_probe(const void *fdt, int node,
378 const void *comp_data)
379 {
380 struct stm32_rproc_instance *rproc = NULL;
381 TEE_Result res = TEE_ERROR_GENERIC;
382
383 rproc = calloc(1, sizeof(*rproc));
384 if (!rproc)
385 return TEE_ERROR_OUT_OF_MEMORY;
386
387 rproc->cdata = comp_data;
388
389 res = stm32_rproc_parse_mems(rproc, fdt, node);
390 if (res)
391 goto err;
392
393 res = rstctrl_dt_get_by_name(fdt, node, "mcu_rst", &rproc->mcu_rst);
394 if (res)
395 goto err;
396
397 res = rstctrl_dt_get_by_name(fdt, node, "hold_boot", &rproc->hold_boot);
398 if (res)
399 goto err;
400
401 /* Ensure that the MCU is HOLD */
402 if (rproc->mcu_rst) {
403 res = rproc_stop(rproc);
404 if (res)
405 goto err;
406 }
407
408 if (!stm32_rcc_is_secure()) {
409 IMSG("WARNING: insecure rproc isolation, RCC is not secure");
410 if (!IS_ENABLED(CFG_INSECURE))
411 panic();
412 } else {
413 stm32_rcc_set_mckprot(true);
414 }
415
416 /*
417 * The memory management should be enhance with firewall
418 * mechanism to map the memory in secure area for the firmware
419 * loading and then to give exclusive access right to the
420 * coprocessor (except for the shared memory).
421 */
422 IMSG("Warning: the remoteproc memories are not protected by firewall");
423
424 SLIST_INSERT_HEAD(&rproc_list, rproc, link);
425
426 return TEE_SUCCESS;
427
428 err:
429 stm32_rproc_cleanup(rproc);
430 return res;
431 }
432
433 static const struct stm32_rproc_compat_data stm32_rproc_m4_compat = {
434 .rproc_id = STM32_M4_RPROC_ID,
435 .ns_loading = false,
436 };
437
438 static const struct dt_device_match stm32_rproc_match_table[] = {
439 {
440 .compatible = "st,stm32mp1-m4-tee",
441 .compat_data = &stm32_rproc_m4_compat,
442 },
443 { }
444 };
445
446 DEFINE_DT_DRIVER(stm32_rproc_dt_driver) = {
447 .name = "stm32-rproc",
448 .match_table = stm32_rproc_match_table,
449 .probe = &stm32_rproc_probe,
450 };
451