1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <metal/alloc.h>
10 #include <metal/log.h>
11 #include <metal/utilities.h>
12 #include <openamp/elf_loader.h>
13 #include <openamp/remoteproc.h>
14 #include <openamp/remoteproc_loader.h>
15 #include <openamp/remoteproc_virtio.h>
16 #include <openamp/rsc_table_parser.h>
17
18 /******************************************************************************
19 * static functions
20 *****************************************************************************/
21 static struct loader_ops *
remoteproc_check_fw_format(const void * img_data,size_t img_len)22 remoteproc_check_fw_format(const void *img_data, size_t img_len)
23 {
24 if (img_len <= 0)
25 return NULL;
26 else if (elf_identify(img_data, img_len) == 0)
27 return &elf_ops;
28 else
29 return NULL;
30 }
31
32 static struct remoteproc_mem *
remoteproc_get_mem(struct remoteproc * rproc,const char * name,metal_phys_addr_t pa,metal_phys_addr_t da,void * va,size_t size)33 remoteproc_get_mem(struct remoteproc *rproc, const char *name,
34 metal_phys_addr_t pa, metal_phys_addr_t da,
35 void *va, size_t size)
36 {
37 struct metal_list *node;
38 struct remoteproc_mem *mem;
39
40 metal_list_for_each(&rproc->mems, node) {
41 mem = metal_container_of(node, struct remoteproc_mem, node);
42 if (name) {
43 if (!strncmp(name, mem->name, sizeof(mem->name)))
44 return mem;
45 } else if (pa != METAL_BAD_PHYS) {
46 metal_phys_addr_t pa_start, pa_end;
47
48 pa_start = mem->pa;
49 pa_end = pa_start + mem->size;
50 if (pa >= pa_start && (pa + size) <= pa_end)
51 return mem;
52 } else if (da != METAL_BAD_PHYS) {
53 metal_phys_addr_t da_start, da_end;
54
55 da_start = mem->da;
56 da_end = da_start + mem->size;
57 if (da >= da_start && (da + size) <= da_end)
58 return mem;
59 } else if (va) {
60 if (metal_io_virt_to_offset(mem->io, va) !=
61 METAL_BAD_OFFSET)
62 return mem;
63
64 } else {
65 return NULL;
66 }
67 }
68 return NULL;
69 }
70
71 static metal_phys_addr_t
remoteproc_datopa(struct remoteproc_mem * mem,metal_phys_addr_t da)72 remoteproc_datopa(struct remoteproc_mem *mem, metal_phys_addr_t da)
73 {
74 metal_phys_addr_t pa;
75
76 pa = mem->pa + da - mem->da;
77 return pa;
78 }
79
80 static metal_phys_addr_t
remoteproc_patoda(struct remoteproc_mem * mem,metal_phys_addr_t pa)81 remoteproc_patoda(struct remoteproc_mem *mem, metal_phys_addr_t pa)
82 {
83 metal_phys_addr_t da;
84
85 da = mem->da + pa - mem->pa;
86 return da;
87 }
88
remoteproc_get_rsc_table(struct remoteproc * rproc,void * store,struct image_store_ops * store_ops,size_t offset,size_t len)89 static void *remoteproc_get_rsc_table(struct remoteproc *rproc,
90 void *store,
91 struct image_store_ops *store_ops,
92 size_t offset,
93 size_t len)
94 {
95 int ret;
96 void *rsc_table = NULL;
97 const void *img_data;
98
99 /* Copy the resource table to local memory,
100 * the caller should be responsible to release the memory
101 */
102 rsc_table = metal_allocate_memory(len);
103 if (!rsc_table) {
104 return RPROC_ERR_PTR(-RPROC_ENOMEM);
105 }
106 ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR,
107 NULL, 1);
108 if (ret < 0 || ret < (int)len || img_data == NULL) {
109 metal_log(METAL_LOG_ERROR,
110 "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len);
111 rsc_table = RPROC_ERR_PTR(-RPROC_EINVAL);
112 goto error;
113 }
114 memcpy(rsc_table, img_data, len);
115
116 ret = handle_rsc_table(rproc, rsc_table, len, NULL);
117 if (ret < 0) {
118 rsc_table = RPROC_ERR_PTR(ret);
119 goto error;
120 }
121 return rsc_table;
122
123 error:
124 metal_free_memory(rsc_table);
125 return rsc_table;
126 }
127
remoteproc_parse_rsc_table(struct remoteproc * rproc,struct resource_table * rsc_table,size_t rsc_size)128 int remoteproc_parse_rsc_table(struct remoteproc *rproc,
129 struct resource_table *rsc_table,
130 size_t rsc_size)
131 {
132 struct metal_io_region *io;
133
134 io = remoteproc_get_io_with_va(rproc, (void *)rsc_table);
135 return handle_rsc_table(rproc, rsc_table, rsc_size, io);
136 }
137
remoteproc_set_rsc_table(struct remoteproc * rproc,struct resource_table * rsc_table,size_t rsc_size)138 int remoteproc_set_rsc_table(struct remoteproc *rproc,
139 struct resource_table *rsc_table,
140 size_t rsc_size)
141 {
142 int ret;
143 struct metal_io_region *io;
144
145 io = remoteproc_get_io_with_va(rproc, (void *)rsc_table);
146 if (!io)
147 return -EINVAL;
148 ret = remoteproc_parse_rsc_table(rproc, rsc_table, rsc_size);
149 if (!ret) {
150 rproc->rsc_table = rsc_table;
151 rproc->rsc_len = rsc_size;
152 rproc->rsc_io = io;
153 }
154 return ret;
155
156 }
157
remoteproc_init(struct remoteproc * rproc,struct remoteproc_ops * ops,void * priv)158 struct remoteproc *remoteproc_init(struct remoteproc *rproc,
159 struct remoteproc_ops *ops, void *priv)
160 {
161 if (rproc) {
162 memset(rproc, 0, sizeof (*rproc));
163 rproc->state = RPROC_OFFLINE;
164 metal_mutex_init(&rproc->lock);
165 metal_list_init(&rproc->mems);
166 metal_list_init(&rproc->vdevs);
167 }
168 rproc = ops->init(rproc, ops, priv);
169 return rproc;
170 }
171
remoteproc_remove(struct remoteproc * rproc)172 int remoteproc_remove(struct remoteproc *rproc)
173 {
174 int ret;
175
176 if (rproc) {
177 metal_mutex_acquire(&rproc->lock);
178 if (rproc->state == RPROC_OFFLINE)
179 rproc->ops->remove(rproc);
180 else
181 ret = -EBUSY;
182 metal_mutex_release(&rproc->lock);
183 } else {
184 ret = -EINVAL;
185 }
186 return ret;
187 }
188
remoteproc_config(struct remoteproc * rproc,void * data)189 int remoteproc_config(struct remoteproc *rproc, void *data)
190 {
191 int ret = -RPROC_ENODEV;
192
193 if (rproc) {
194 metal_mutex_acquire(&rproc->lock);
195 if (rproc->state == RPROC_OFFLINE) {
196 /* configure operation is allowed if the state is
197 * offline or ready. This function can be called
198 * mulitple times before start the remote.
199 */
200 if (rproc->ops->config)
201 ret = rproc->ops->config(rproc, data);
202 rproc->state = RPROC_READY;
203 } else {
204 ret = -RPROC_EINVAL;
205 }
206 metal_mutex_release(&rproc->lock);
207 }
208 return ret;
209 }
210
remoteproc_start(struct remoteproc * rproc)211 int remoteproc_start(struct remoteproc *rproc)
212 {
213 int ret = -RPROC_ENODEV;
214
215 if (rproc) {
216 metal_mutex_acquire(&rproc->lock);
217 if (rproc->state == RPROC_READY) {
218 ret = rproc->ops->start(rproc);
219 rproc->state = RPROC_RUNNING;
220 } else {
221 ret = -RPROC_EINVAL;
222 }
223 metal_mutex_release(&rproc->lock);
224 }
225 return ret;
226 }
227
remoteproc_stop(struct remoteproc * rproc)228 int remoteproc_stop(struct remoteproc *rproc)
229 {
230 int ret = -RPROC_ENODEV;
231
232 if (rproc) {
233 metal_mutex_acquire(&rproc->lock);
234 if (rproc->state != RPROC_STOPPED &&
235 rproc->state != RPROC_OFFLINE) {
236 if (rproc->ops->stop)
237 ret = rproc->ops->stop(rproc);
238 rproc->state = RPROC_STOPPED;
239 } else {
240 ret = 0;
241 }
242 metal_mutex_release(&rproc->lock);
243 }
244 return ret;
245 }
246
remoteproc_shutdown(struct remoteproc * rproc)247 int remoteproc_shutdown(struct remoteproc *rproc)
248 {
249 int ret = -RPROC_ENODEV;
250
251 if (rproc) {
252 ret = 0;
253 metal_mutex_acquire(&rproc->lock);
254 if (rproc->state != RPROC_OFFLINE) {
255 if (rproc->state != RPROC_STOPPED) {
256 if (rproc->ops->stop)
257 ret = rproc->ops->stop(rproc);
258 }
259 if (!ret) {
260 if (rproc->ops->shutdown)
261 ret = rproc->ops->shutdown(rproc);
262 if (!ret) {
263 rproc->state = RPROC_OFFLINE;
264 }
265 }
266 }
267 metal_mutex_release(&rproc->lock);
268 }
269 return ret;
270 }
271
272 struct metal_io_region *
remoteproc_get_io_with_name(struct remoteproc * rproc,const char * name)273 remoteproc_get_io_with_name(struct remoteproc *rproc,
274 const char *name)
275 {
276 struct remoteproc_mem *mem;
277
278 mem = remoteproc_get_mem(rproc, name,
279 METAL_BAD_PHYS, METAL_BAD_PHYS, NULL, 0);
280 if (mem)
281 return mem->io;
282 else
283 return NULL;
284 }
285
286 struct metal_io_region *
remoteproc_get_io_with_pa(struct remoteproc * rproc,metal_phys_addr_t pa)287 remoteproc_get_io_with_pa(struct remoteproc *rproc,
288 metal_phys_addr_t pa)
289 {
290 struct remoteproc_mem *mem;
291
292 mem = remoteproc_get_mem(rproc, NULL, pa, METAL_BAD_PHYS, NULL, 0);
293 if (mem)
294 return mem->io;
295 else
296 return NULL;
297 }
298
299 struct metal_io_region *
remoteproc_get_io_with_da(struct remoteproc * rproc,metal_phys_addr_t da,unsigned long * offset)300 remoteproc_get_io_with_da(struct remoteproc *rproc,
301 metal_phys_addr_t da,
302 unsigned long *offset)
303 {
304 struct remoteproc_mem *mem;
305
306 mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, da, NULL, 0);
307 if (mem) {
308 struct metal_io_region *io;
309 metal_phys_addr_t pa;
310
311 io = mem->io;
312 pa = remoteproc_datopa(mem, da);
313 *offset = metal_io_phys_to_offset(io, pa);
314 return io;
315 } else {
316 return NULL;
317 }
318 }
319
320 struct metal_io_region *
remoteproc_get_io_with_va(struct remoteproc * rproc,void * va)321 remoteproc_get_io_with_va(struct remoteproc *rproc, void *va)
322 {
323 struct remoteproc_mem *mem;
324
325 mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, METAL_BAD_PHYS,
326 va, 0);
327 if (mem)
328 return mem->io;
329 else
330 return NULL;
331 }
332
remoteproc_mmap(struct remoteproc * rproc,metal_phys_addr_t * pa,metal_phys_addr_t * da,size_t size,unsigned int attribute,struct metal_io_region ** io)333 void *remoteproc_mmap(struct remoteproc *rproc,
334 metal_phys_addr_t *pa, metal_phys_addr_t *da,
335 size_t size, unsigned int attribute,
336 struct metal_io_region **io)
337 {
338 void *va = NULL;
339 metal_phys_addr_t lpa, lda;
340 struct remoteproc_mem *mem;
341
342 if (!rproc)
343 return NULL;
344 else if (!pa && !da)
345 return NULL;
346 if (pa)
347 lpa = *pa;
348 else
349 lpa = METAL_BAD_PHYS;
350 if (da)
351 lda = *da;
352 else
353 lda = METAL_BAD_PHYS;
354 mem = remoteproc_get_mem(rproc, NULL, lpa, lda, NULL, size);
355 if (mem) {
356 if (lpa != METAL_BAD_PHYS)
357 lda = remoteproc_patoda(mem, lpa);
358 else if (lda != METAL_BAD_PHYS)
359 lpa = remoteproc_datopa(mem, lda);
360 if (io)
361 *io = mem->io;
362 va = metal_io_phys_to_virt(mem->io, lpa);
363 } else if (rproc->ops->mmap) {
364 va = rproc->ops->mmap(rproc, &lpa, &lda, size, attribute, io);
365 }
366
367 if (pa)
368 *pa = lpa;
369 if (da)
370 *da = lda;
371 return va;
372 }
373
remoteproc_load(struct remoteproc * rproc,const char * path,void * store,struct image_store_ops * store_ops,void ** img_info)374 int remoteproc_load(struct remoteproc *rproc, const char *path,
375 void *store, struct image_store_ops *store_ops,
376 void **img_info)
377 {
378 int ret;
379 struct loader_ops *loader;
380 const void *img_data;
381 void *limg_info = NULL;
382 size_t offset, noffset;
383 size_t len, nlen;
384 int last_load_state;
385 metal_phys_addr_t da, rsc_da;
386 int rsc_len;
387 size_t rsc_size;
388 void *rsc_table = NULL;
389 struct metal_io_region *io = NULL;
390
391 if (!rproc)
392 return -RPROC_ENODEV;
393
394 metal_mutex_acquire(&rproc->lock);
395 metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__);
396 /* If remoteproc is not in ready state, cannot load executable */
397 if (rproc->state != RPROC_READY && rproc->state != RPROC_CONFIGURED) {
398 metal_log(METAL_LOG_ERROR,
399 "load failure: invalid rproc state %d.\r\n",
400 rproc->state);
401 metal_mutex_release(&rproc->lock);
402 return -RPROC_EINVAL;
403 }
404
405 if (!store_ops) {
406 metal_log(METAL_LOG_ERROR,
407 "load failure: loader ops is not set.\r\n");
408 metal_mutex_release(&rproc->lock);
409 return -RPROC_EINVAL;
410 }
411
412 /* Open exectuable to get ready to parse */
413 metal_log(METAL_LOG_DEBUG, "%s: open exectuable image\r\n", __func__);
414 ret = store_ops->open(store, path, &img_data);
415 if (ret <= 0) {
416 metal_log(METAL_LOG_ERROR,
417 "load failure: failed to open firmware %d.\n",
418 ret);
419 metal_mutex_release(&rproc->lock);
420 return -RPROC_EINVAL;
421 }
422 len = ret;
423 metal_assert(img_data != NULL);
424
425 /* Check executable format to select a parser */
426 loader = rproc->loader;
427 if (!loader) {
428 metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__);
429 loader = remoteproc_check_fw_format(img_data, len);
430 if (!loader) {
431 metal_log(METAL_LOG_ERROR,
432 "load failure: failed to get store ops.\n");
433 ret = -RPROC_EINVAL;
434 goto error1;
435 }
436 rproc->loader = loader;
437 }
438
439 /* Load exectuable headers */
440 metal_log(METAL_LOG_DEBUG, "%s: loading headers\r\n", __func__);
441 offset = 0;
442 last_load_state = RPROC_LOADER_NOT_READY;
443 while(1) {
444 ret = loader->load_header(img_data, offset, len,
445 &limg_info, last_load_state,
446 &noffset, &nlen);
447 last_load_state = (unsigned int)ret;
448 metal_log(METAL_LOG_DEBUG,
449 "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
450 __func__, offset, len, noffset, nlen);
451 if (ret < 0) {
452 metal_log(METAL_LOG_ERROR,
453 "load header failed 0x%lx,%d.\r\n",
454 offset, len);
455
456 goto error2;
457 } else if ((ret & RPROC_LOADER_READY_TO_LOAD) != 0) {
458 if (nlen == 0)
459 break;
460 else if ((noffset > (offset + len)) &&
461 (store_ops->features & SUPPORT_SEEK) == 0) {
462 /* Required data is not continued, however
463 * seek is not supported, stop to load
464 * headers such as ELF section headers which
465 * is usually located to the end of image.
466 * Continue to load binary data to target
467 * memory.
468 */
469 break;
470 }
471 }
472 /* Continue to load headers image data */
473 img_data = NULL;
474 ret = store_ops->load(store, noffset, nlen,
475 &img_data,
476 RPROC_LOAD_ANYADDR,
477 NULL, 1);
478 if (ret < (int)nlen) {
479 metal_log(METAL_LOG_ERROR,
480 "load image data failed 0x%x,%d\r\n",
481 noffset, nlen);
482 goto error2;
483 }
484 offset = noffset;
485 len = nlen;
486 }
487 ret = elf_locate_rsc_table(limg_info, &rsc_da, &offset, &rsc_size);
488 if (ret == 0 && rsc_size > 0) {
489 /* parse resource table */
490 rsc_len = (int)rsc_size;
491 rsc_table = remoteproc_get_rsc_table(rproc, store, store_ops,
492 offset, rsc_len);
493 } else {
494 rsc_len = ret;
495 }
496
497 /* load executable data */
498 metal_log(METAL_LOG_DEBUG, "%s: load executable data\r\n", __func__);
499 offset = 0;
500 len = 0;
501 ret = -EINVAL;
502 while(1) {
503 unsigned char padding;
504 size_t nmemsize;
505 metal_phys_addr_t pa;
506
507 da = RPROC_LOAD_ANYADDR;
508 nlen = 0;
509 nmemsize = 0;
510 noffset = 0;
511 ret = loader->load_data(rproc, img_data, offset, len,
512 &limg_info, last_load_state, &da,
513 &noffset, &nlen, &padding, &nmemsize);
514 if (ret < 0) {
515 metal_log(METAL_LOG_ERROR,
516 "load data failed,0x%lx,%d\r\n",
517 noffset, nlen);
518 goto error3;
519 }
520 metal_log(METAL_LOG_DEBUG,
521 "load data: da 0x%lx, offset 0x%lx, len = 0x%lx, memsize = 0x%lx, state 0x%x\r\n",
522 da, noffset, nlen, nmemsize, ret);
523 last_load_state = ret;
524 if (da != RPROC_LOAD_ANYADDR) {
525 /* Data is supposed to be loaded to target memory */
526 img_data = NULL;
527 /* get the I/O region from remoteproc */
528 pa = METAL_BAD_PHYS;
529 (void)remoteproc_mmap(rproc, &pa, &da, nmemsize, 0, &io);
530 if (pa == METAL_BAD_PHYS || io == NULL) {
531 metal_log(METAL_LOG_ERROR,
532 "load failed, no mapping for 0x%llx.\r\n",
533 da);
534 ret = -RPROC_EINVAL;
535 goto error3;
536 }
537 if (nlen > 0) {
538 ret = store_ops->load(store, noffset, nlen,
539 &img_data, pa, io, 1);
540 if (ret != (int)nlen) {
541 metal_log(METAL_LOG_ERROR,
542 "load data failed 0x%lx, 0x%lx, 0x%x\r\n",
543 pa, noffset, nlen);
544 ret = -RPROC_EINVAL;
545 goto error3;
546 }
547 }
548 if (nmemsize > nlen) {
549 size_t tmpoffset;
550
551 tmpoffset = metal_io_phys_to_offset(io,
552 pa + nlen);
553 metal_io_block_set(io, tmpoffset,
554 padding, (nmemsize - nlen));
555 }
556 } else if (nlen != 0) {
557 ret = store_ops->load(store, noffset, nlen,
558 &img_data,
559 RPROC_LOAD_ANYADDR,
560 NULL, 1);
561 if (ret < (int)nlen) {
562 if ((last_load_state &
563 RPROC_LOADER_POST_DATA_LOAD) != 0) {
564 metal_log(METAL_LOG_WARNING,
565 "not all the headers are loaded\r\n");
566 break;
567 }
568 metal_log(METAL_LOG_ERROR,
569 "post-load image data failed 0x%x,%d\r\n",
570 noffset, nlen);
571 goto error3;
572 }
573 offset = noffset;
574 len = nlen;
575 } else {
576 /* (last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0 */
577 break;
578 }
579 }
580
581 if (rsc_len < 0) {
582 ret = elf_locate_rsc_table(limg_info, &rsc_da,
583 &offset, &rsc_size);
584 if (ret == 0 && rsc_size > 0) {
585 /* parse resource table */
586 rsc_len = (int)rsc_size;
587 rsc_table = remoteproc_get_rsc_table(rproc, store,
588 store_ops,
589 offset,
590 rsc_len);
591 }
592 }
593
594 /* Update resource table */
595 if (rsc_len && rsc_da != METAL_BAD_PHYS) {
596 void *rsc_table_cp = rsc_table;
597
598 metal_log(METAL_LOG_DEBUG,
599 "%s, update resource table\r\n", __func__);
600 rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da,
601 rsc_len, 0, &io);
602 if (rsc_table) {
603 size_t rsc_io_offset;
604
605 /* Update resource table */
606 rsc_io_offset = metal_io_virt_to_offset(io, rsc_table);
607 ret = metal_io_block_write(io, rsc_io_offset,
608 rsc_table_cp, rsc_len);
609 if (ret != rsc_len) {
610 metal_log(METAL_LOG_WARNING,
611 "load: failed to update rsc\r\n");
612 }
613 rproc->rsc_table = rsc_table;
614 rproc->rsc_len = rsc_len;
615 } else {
616 metal_log(METAL_LOG_WARNING,
617 "load: not able to update rsc table.\n");
618 }
619 metal_free_memory(rsc_table_cp);
620 /* So that the rsc_table will not get released */
621 rsc_table = NULL;
622 }
623
624 metal_log(METAL_LOG_DEBUG, "%s: successfully load firmware\r\n",
625 __func__);
626 /* get entry point from the firmware */
627 rproc->bootaddr = loader->get_entry(limg_info);
628 rproc->state = RPROC_READY;
629
630 metal_mutex_release(&rproc->lock);
631 if (img_info)
632 *img_info = limg_info;
633 else
634 loader->release(limg_info);
635 store_ops->close(store);
636 return 0;
637
638 error3:
639 if (rsc_table)
640 metal_free_memory(rsc_table);
641 error2:
642 loader->release(limg_info);
643 error1:
644 store_ops->close(store);
645 metal_mutex_release(&rproc->lock);
646 return ret;
647 }
648
remoteproc_load_noblock(struct remoteproc * rproc,const void * img_data,size_t offset,size_t len,void ** img_info,metal_phys_addr_t * pa,struct metal_io_region ** io,size_t * noffset,size_t * nlen,size_t * nmlen,unsigned char * padding)649 int remoteproc_load_noblock(struct remoteproc *rproc,
650 const void *img_data, size_t offset, size_t len,
651 void **img_info,
652 metal_phys_addr_t *pa, struct metal_io_region **io,
653 size_t *noffset, size_t *nlen,
654 size_t *nmlen, unsigned char *padding)
655 {
656 int ret;
657 struct loader_ops *loader;
658 void *limg_info = NULL;
659 int last_load_state;
660 metal_phys_addr_t da, rsc_da;
661 size_t rsc_size;
662 void *rsc_table = NULL, *lrsc_table = NULL;
663
664 if (!rproc)
665 return -RPROC_ENODEV;
666
667 metal_assert(pa != NULL);
668 metal_assert(io != NULL);
669 metal_assert(noffset != NULL);
670 metal_assert(nlen != NULL);
671 metal_assert(nmlen != NULL);
672 metal_assert(padding != NULL);
673
674 metal_mutex_acquire(&rproc->lock);
675 metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__);
676 /* If remoteproc is not in ready state, cannot load executable */
677 if (rproc->state != RPROC_READY) {
678 metal_log(METAL_LOG_ERROR,
679 "load failure: invalid rproc state %d.\r\n",
680 rproc->state);
681 metal_mutex_release(&rproc->lock);
682 return -RPROC_EINVAL;
683 }
684
685 /* Check executable format to select a parser */
686 loader = rproc->loader;
687 if (!loader) {
688 metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__);
689 if (img_data == NULL || offset != 0 || len == 0) {
690 metal_log(METAL_LOG_ERROR,
691 "load failure, invalid inputs, not able to identify image.\r\n");
692 metal_mutex_release(&rproc->lock);
693 return -RPROC_EINVAL;
694 }
695 loader = remoteproc_check_fw_format(img_data, len);
696 if (!loader) {
697 metal_log(METAL_LOG_ERROR,
698 "load failure: failed to identify image.\n");
699 ret = -RPROC_EINVAL;
700 metal_mutex_release(&rproc->lock);
701 return -RPROC_EINVAL;
702 }
703 rproc->loader = loader;
704 }
705 if (img_info == NULL || *img_info == NULL ) {
706 last_load_state = 0;
707 } else {
708 limg_info = *img_info;
709 last_load_state = loader->get_load_state(limg_info);
710 if (last_load_state < 0) {
711 metal_log(METAL_LOG_ERROR,
712 "load failure, not able get load state.\r\n");
713 metal_mutex_release(&rproc->lock);
714 return -RPROC_EINVAL;
715 }
716 }
717 da = RPROC_LOAD_ANYADDR;
718 *nlen = 0;
719 if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0 &&
720 (last_load_state & RPROC_LOADER_LOAD_COMPLETE) == 0) {
721 /* Get the mandatory executable headers */
722 ret = loader->load_header(img_data, offset, len,
723 &limg_info, last_load_state,
724 noffset, nlen);
725 last_load_state = (unsigned int)ret;
726 metal_log(METAL_LOG_DEBUG,
727 "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
728 __func__, offset, len, *noffset, *nlen);
729 if (ret < 0) {
730 metal_log(METAL_LOG_ERROR,
731 "load header failed 0x%lx,%d.\r\n",
732 offset, len);
733
734 goto error1;
735 }
736 last_load_state = loader->get_load_state(limg_info);
737 if (*nlen != 0 &&
738 (last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0)
739 goto out;
740 }
741 if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) != 0 ||
742 (last_load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) {
743 /* Enough information to know which target memory for
744 * which data.
745 */
746 ret = loader->load_data(rproc, img_data, offset, len,
747 &limg_info, last_load_state, &da,
748 noffset, nlen, padding, nmlen);
749 metal_log(METAL_LOG_DEBUG,
750 "%s, load data 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
751 __func__, offset, len, *noffset, *nlen);
752 if (ret < 0) {
753 metal_log(METAL_LOG_ERROR,
754 "load data failed,0x%lx,%d\r\n",
755 offset, len);
756 goto error1;
757 }
758 if (da != RPROC_LOAD_ANYADDR) {
759 /* get the I/O region from remoteproc */
760 *pa = METAL_BAD_PHYS;
761 (void)remoteproc_mmap(rproc, pa, &da, *nmlen, 0, io);
762 if (*pa == METAL_BAD_PHYS || io == NULL) {
763 metal_log(METAL_LOG_ERROR,
764 "load failed, no mapping for 0x%llx.\r\n",
765 da);
766 ret = -RPROC_EINVAL;
767 goto error1;
768 }
769 }
770 if (*nlen != 0)
771 goto out;
772 else
773 last_load_state = loader->get_load_state(limg_info);
774 }
775 if ((last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0) {
776 /* Get resource table */
777 size_t rsc_offset;
778 size_t rsc_io_offset;
779
780 ret = elf_locate_rsc_table(limg_info, &rsc_da,
781 &rsc_offset, &rsc_size);
782 if (ret == 0 && rsc_size > 0) {
783 lrsc_table = metal_allocate_memory(rsc_size);
784 if (lrsc_table == NULL) {
785 ret = -RPROC_ENOMEM;
786 goto error1;
787 }
788 rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da,
789 rsc_size, 0, io);
790 if (*io == NULL) {
791 metal_log(METAL_LOG_ERROR,
792 "load failed: failed to mmap rsc\r\n");
793 metal_free_memory(lrsc_table);
794 goto error1;
795 }
796 rsc_io_offset = metal_io_virt_to_offset(*io, rsc_table);
797 ret = metal_io_block_read(*io, rsc_io_offset,
798 lrsc_table, (int)rsc_size);
799 if (ret != (int)rsc_size) {
800 metal_log(METAL_LOG_ERROR,
801 "load failed: failed to get rsc\r\n");
802 metal_free_memory(lrsc_table);
803 goto error1;
804 }
805 /* parse resource table */
806 ret = remoteproc_parse_rsc_table(rproc, lrsc_table,
807 rsc_size);
808 if (ret == (int)rsc_size) {
809 metal_log(METAL_LOG_ERROR,
810 "load failed: failed to parse rsc\r\n");
811 metal_free_memory(lrsc_table);
812 goto error1;
813 }
814 /* Update resource table */
815 ret = metal_io_block_write(*io, rsc_io_offset,
816 lrsc_table, (int)rsc_size);
817 if (ret != (int)rsc_size) {
818 metal_log(METAL_LOG_WARNING,
819 "load exectuable, failed to update rsc\r\n");
820 }
821 rproc->rsc_table = rsc_table;
822 rproc->rsc_len = (int)rsc_size;
823 metal_free_memory(lrsc_table);
824 }
825 }
826 out:
827 if (img_info != NULL)
828 *img_info = limg_info;
829 else
830 loader->release(limg_info);
831 metal_mutex_release(&rproc->lock);
832 return 0;
833
834 error1:
835 loader->release(limg_info);
836 metal_mutex_release(&rproc->lock);
837 return ret;
838 }
839
remoteproc_allocate_id(struct remoteproc * rproc,unsigned int start,unsigned int end)840 unsigned int remoteproc_allocate_id(struct remoteproc *rproc,
841 unsigned int start,
842 unsigned int end)
843 {
844 unsigned int notifyid;
845
846 if (start == RSC_NOTIFY_ID_ANY)
847 start = 0;
848 if (end == RSC_NOTIFY_ID_ANY)
849 end = METAL_BITS_PER_ULONG;
850 notifyid = metal_bitmap_next_set_bit(&rproc->bitmap,
851 start, end);
852 if (notifyid != end)
853 metal_bitmap_set_bit(&rproc->bitmap, notifyid);
854 return notifyid;
855 }
856
remoteproc_virtio_notify(void * priv,uint32_t id)857 static int remoteproc_virtio_notify(void *priv, uint32_t id)
858 {
859 struct remoteproc *rproc = priv;
860
861 return rproc->ops->notify(rproc, id);
862 }
863
864 struct virtio_device *
remoteproc_create_virtio(struct remoteproc * rproc,int vdev_id,unsigned int role,void (* rst_cb)(struct virtio_device * vdev))865 remoteproc_create_virtio(struct remoteproc *rproc,
866 int vdev_id, unsigned int role,
867 void (*rst_cb)(struct virtio_device *vdev))
868 {
869 char *rsc_table;
870 struct fw_rsc_vdev *vdev_rsc;
871 struct metal_io_region *vdev_rsc_io;
872 struct virtio_device *vdev;
873 struct remoteproc_virtio *rpvdev;
874 size_t vdev_rsc_offset;
875 unsigned int notifyid;
876 unsigned int num_vrings, i;
877 struct metal_list *node;
878
879 metal_assert(rproc);
880 metal_mutex_acquire(&rproc->lock);
881 rsc_table = rproc->rsc_table;
882 vdev_rsc_io = rproc->rsc_io;
883 vdev_rsc_offset = find_rsc(rsc_table, RSC_VDEV, vdev_id);
884 if (!vdev_rsc_offset) {
885 metal_mutex_release(&rproc->lock);
886 return NULL;
887 }
888 vdev_rsc = (struct fw_rsc_vdev *)(rsc_table + vdev_rsc_offset);
889 notifyid = vdev_rsc->notifyid;
890 /* Check if the virtio device is already created */
891 metal_list_for_each(&rproc->vdevs, node) {
892 rpvdev = metal_container_of(node, struct remoteproc_virtio,
893 node);
894 if (rpvdev->vdev.index == notifyid)
895 return &rpvdev->vdev;
896 }
897 vdev = rproc_virtio_create_vdev(role, notifyid,
898 vdev_rsc, vdev_rsc_io, rproc,
899 remoteproc_virtio_notify,
900 rst_cb);
901 rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
902 metal_list_add_tail(&rproc->vdevs, &rpvdev->node);
903 num_vrings = vdev_rsc->num_of_vrings;
904 /* set the notification id for vrings */
905 for (i = 0; i < num_vrings; i++) {
906 struct fw_rsc_vdev_vring *vring_rsc;
907 metal_phys_addr_t da;
908 unsigned int num_descs, align;
909 struct metal_io_region *io;
910 void *va;
911 size_t size;
912 int ret;
913
914 vring_rsc = &vdev_rsc->vring[i];
915 notifyid = vring_rsc->notifyid;
916 da = vring_rsc->da;
917 num_descs = vring_rsc->num;
918 align = vring_rsc->align;
919 size = vring_size(num_descs, align);
920 va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io);
921 if (!va)
922 goto err1;
923 ret = rproc_virtio_init_vring(vdev, i, notifyid,
924 va, io, num_descs, align);
925 if (ret)
926 goto err1;
927 }
928 metal_mutex_release(&rproc->lock);
929 return vdev;
930
931 err1:
932 remoteproc_remove_virtio(rproc, vdev);
933 metal_mutex_release(&rproc->lock);
934 return NULL;
935 }
936
remoteproc_remove_virtio(struct remoteproc * rproc,struct virtio_device * vdev)937 void remoteproc_remove_virtio(struct remoteproc *rproc,
938 struct virtio_device *vdev)
939 {
940 struct remoteproc_virtio *rpvdev;
941
942 (void)rproc;
943 metal_assert(vdev);
944 rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
945 metal_list_del(&rpvdev->node);
946 rproc_virtio_remove_vdev(&rpvdev->vdev);
947 }
948
remoteproc_get_notification(struct remoteproc * rproc,uint32_t notifyid)949 int remoteproc_get_notification(struct remoteproc *rproc, uint32_t notifyid)
950 {
951 struct remoteproc_virtio *rpvdev;
952 struct metal_list *node;
953 int ret;
954
955 metal_list_for_each(&rproc->vdevs, node) {
956 rpvdev = metal_container_of(node, struct remoteproc_virtio,
957 node);
958 ret = rproc_virtio_notified(&rpvdev->vdev, notifyid);
959 if (ret)
960 return ret;
961 }
962 return 0;
963 }
964