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