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