1 /*
2  * dbll.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Copyright (C) 2005-2006 Texas Instruments, Inc.
7  *
8  * This package is free software;  you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15  */
16 #include <linux/types.h>
17 
18 /*  ----------------------------------- Host OS */
19 #include <dspbridge/host_os.h>
20 
21 /*  ----------------------------------- DSP/BIOS Bridge */
22 #include <dspbridge/dbdefs.h>
23 
24 /*  ----------------------------------- Trace & Debug */
25 #include <dspbridge/dbc.h>
26 #include <dspbridge/gh.h>
27 
28 /*  ----------------------------------- OS Adaptation Layer */
29 
30 /* Dynamic loader library interface */
31 #include <dspbridge/dynamic_loader.h>
32 #include <dspbridge/getsection.h>
33 
34 /*  ----------------------------------- This */
35 #include <dspbridge/dbll.h>
36 #include <dspbridge/rmm.h>
37 
38 /* Number of buckets for symbol hash table */
39 #define MAXBUCKETS 211
40 
41 /* Max buffer length */
42 #define MAXEXPR 128
43 
44 #define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
45 
46 /*
47  *  ======== struct dbll_tar_obj* ========
48  *  A target may have one or more libraries of symbols/code/data loaded
49  *  onto it, where a library is simply the symbols/code/data contained
50  *  in a DOFF file.
51  */
52 /*
53  *  ======== dbll_tar_obj ========
54  */
55 struct dbll_tar_obj {
56 	struct dbll_attrs attrs;
57 	struct dbll_library_obj *head;	/* List of all opened libraries */
58 };
59 
60 /*
61  *  The following 4 typedefs are "super classes" of the dynamic loader
62  *  library types used in dynamic loader functions (dynamic_loader.h).
63  */
64 /*
65  *  ======== dbll_stream ========
66  *  Contains dynamic_loader_stream
67  */
68 struct dbll_stream {
69 	struct dynamic_loader_stream dl_stream;
70 	struct dbll_library_obj *lib;
71 };
72 
73 /*
74  *  ======== ldr_symbol ========
75  */
76 struct ldr_symbol {
77 	struct dynamic_loader_sym dl_symbol;
78 	struct dbll_library_obj *lib;
79 };
80 
81 /*
82  *  ======== dbll_alloc ========
83  */
84 struct dbll_alloc {
85 	struct dynamic_loader_allocate dl_alloc;
86 	struct dbll_library_obj *lib;
87 };
88 
89 /*
90  *  ======== dbll_init_obj ========
91  */
92 struct dbll_init_obj {
93 	struct dynamic_loader_initialize dl_init;
94 	struct dbll_library_obj *lib;
95 };
96 
97 /*
98  *  ======== DBLL_Library ========
99  *  A library handle is returned by DBLL_Open() and is passed to dbll_load()
100  *  to load symbols/code/data, and to dbll_unload(), to remove the
101  *  symbols/code/data loaded by dbll_load().
102  */
103 
104 /*
105  *  ======== dbll_library_obj ========
106  */
107 struct dbll_library_obj {
108 	struct dbll_library_obj *next;	/* Next library in target's list */
109 	struct dbll_library_obj *prev;	/* Previous in the list */
110 	struct dbll_tar_obj *target_obj;	/* target for this library */
111 
112 	/* Objects needed by dynamic loader */
113 	struct dbll_stream stream;
114 	struct ldr_symbol symbol;
115 	struct dbll_alloc allocate;
116 	struct dbll_init_obj init;
117 	void *dload_mod_obj;
118 
119 	char *file_name;	/* COFF file name */
120 	void *fp;		/* Opaque file handle */
121 	u32 entry;		/* Entry point */
122 	void *desc;	/* desc of DOFF file loaded */
123 	u32 open_ref;		/* Number of times opened */
124 	u32 load_ref;		/* Number of times loaded */
125 	struct gh_t_hash_tab *sym_tab;	/* Hash table of symbols */
126 	u32 pos;
127 };
128 
129 /*
130  *  ======== dbll_symbol ========
131  */
132 struct dbll_symbol {
133 	struct dbll_sym_val value;
134 	char *name;
135 };
136 
137 static void dof_close(struct dbll_library_obj *zl_lib);
138 static int dof_open(struct dbll_library_obj *zl_lib);
139 static s32 no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
140 		 ldr_addr locn, struct ldr_section_info *info,
141 		 unsigned bytsize);
142 
143 /*
144  *  Functions called by dynamic loader
145  *
146  */
147 /* dynamic_loader_stream */
148 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
149 			    unsigned bufsize);
150 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
151 			      unsigned int pos);
152 /* dynamic_loader_sym */
153 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
154 					       const char *name);
155 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
156 						       *this, const char *name,
157 						       unsigned module_id);
158 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
159 						   *this, const char *name,
160 						   unsigned moduleid);
161 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
162 				    unsigned module_id);
163 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize);
164 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr);
165 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
166 			    va_list args);
167 /* dynamic_loader_allocate */
168 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
169 			  struct ldr_section_info *info, unsigned align);
170 static void rmm_dealloc(struct dynamic_loader_allocate *this,
171 			struct ldr_section_info *info);
172 
173 /* dynamic_loader_initialize */
174 static int connect(struct dynamic_loader_initialize *this);
175 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
176 		    ldr_addr addr, struct ldr_section_info *info,
177 		    unsigned bytes);
178 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
179 		     ldr_addr addr, struct ldr_section_info *info,
180 		     unsigned nbytes);
181 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
182 		    struct ldr_section_info *info, unsigned bytes,
183 		    unsigned val);
184 static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
185 static void release(struct dynamic_loader_initialize *this);
186 
187 /* symbol table hash functions */
188 static u16 name_hash(void *key, u16 max_bucket);
189 static bool name_match(void *key, void *sp);
190 static void sym_delete(void *value);
191 
192 static u32 refs;		/* module reference count */
193 
194 /* Symbol Redefinition */
195 static int redefined_symbol;
196 static int gbl_search = 1;
197 
198 /*
199  *  ======== dbll_close ========
200  */
dbll_close(struct dbll_library_obj * zl_lib)201 void dbll_close(struct dbll_library_obj *zl_lib)
202 {
203 	struct dbll_tar_obj *zl_target;
204 
205 	DBC_REQUIRE(refs > 0);
206 	DBC_REQUIRE(zl_lib);
207 	DBC_REQUIRE(zl_lib->open_ref > 0);
208 	zl_target = zl_lib->target_obj;
209 	zl_lib->open_ref--;
210 	if (zl_lib->open_ref == 0) {
211 		/* Remove library from list */
212 		if (zl_target->head == zl_lib)
213 			zl_target->head = zl_lib->next;
214 
215 		if (zl_lib->prev)
216 			(zl_lib->prev)->next = zl_lib->next;
217 
218 		if (zl_lib->next)
219 			(zl_lib->next)->prev = zl_lib->prev;
220 
221 		/* Free DOF resources */
222 		dof_close(zl_lib);
223 		kfree(zl_lib->file_name);
224 
225 		/* remove symbols from symbol table */
226 		if (zl_lib->sym_tab)
227 			gh_delete(zl_lib->sym_tab);
228 
229 		/* remove the library object itself */
230 		kfree(zl_lib);
231 		zl_lib = NULL;
232 	}
233 }
234 
235 /*
236  *  ======== dbll_create ========
237  */
dbll_create(struct dbll_tar_obj ** target_obj,struct dbll_attrs * pattrs)238 int dbll_create(struct dbll_tar_obj **target_obj,
239 		       struct dbll_attrs *pattrs)
240 {
241 	struct dbll_tar_obj *pzl_target;
242 	int status = 0;
243 
244 	DBC_REQUIRE(refs > 0);
245 	DBC_REQUIRE(pattrs != NULL);
246 	DBC_REQUIRE(target_obj != NULL);
247 
248 	/* Allocate DBL target object */
249 	pzl_target = kzalloc(sizeof(struct dbll_tar_obj), GFP_KERNEL);
250 	if (target_obj != NULL) {
251 		if (pzl_target == NULL) {
252 			*target_obj = NULL;
253 			status = -ENOMEM;
254 		} else {
255 			pzl_target->attrs = *pattrs;
256 			*target_obj = (struct dbll_tar_obj *)pzl_target;
257 		}
258 		DBC_ENSURE((!status && *target_obj) ||
259 				(status && *target_obj == NULL));
260 	}
261 
262 	return status;
263 }
264 
265 /*
266  *  ======== dbll_delete ========
267  */
dbll_delete(struct dbll_tar_obj * target)268 void dbll_delete(struct dbll_tar_obj *target)
269 {
270 	struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
271 
272 	DBC_REQUIRE(refs > 0);
273 	DBC_REQUIRE(zl_target);
274 
275 	kfree(zl_target);
276 
277 }
278 
279 /*
280  *  ======== dbll_exit ========
281  *  Discontinue usage of DBL module.
282  */
dbll_exit(void)283 void dbll_exit(void)
284 {
285 	DBC_REQUIRE(refs > 0);
286 
287 	refs--;
288 
289 	if (refs == 0)
290 		gh_exit();
291 
292 	DBC_ENSURE(refs >= 0);
293 }
294 
295 /*
296  *  ======== dbll_get_addr ========
297  *  Get address of name in the specified library.
298  */
dbll_get_addr(struct dbll_library_obj * zl_lib,char * name,struct dbll_sym_val ** sym_val)299 bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
300 		   struct dbll_sym_val **sym_val)
301 {
302 	struct dbll_symbol *sym;
303 	bool status = false;
304 
305 	DBC_REQUIRE(refs > 0);
306 	DBC_REQUIRE(zl_lib);
307 	DBC_REQUIRE(name != NULL);
308 	DBC_REQUIRE(sym_val != NULL);
309 	DBC_REQUIRE(zl_lib->sym_tab != NULL);
310 
311 	sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
312 	if (sym != NULL) {
313 		*sym_val = &sym->value;
314 		status = true;
315 	}
316 
317 	dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p, status 0x%x\n",
318 		__func__, zl_lib, name, sym_val, status);
319 	return status;
320 }
321 
322 /*
323  *  ======== dbll_get_attrs ========
324  *  Retrieve the attributes of the target.
325  */
dbll_get_attrs(struct dbll_tar_obj * target,struct dbll_attrs * pattrs)326 void dbll_get_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
327 {
328 	struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
329 
330 	DBC_REQUIRE(refs > 0);
331 	DBC_REQUIRE(zl_target);
332 	DBC_REQUIRE(pattrs != NULL);
333 
334 	if ((pattrs != NULL) && (zl_target != NULL))
335 		*pattrs = zl_target->attrs;
336 
337 }
338 
339 /*
340  *  ======== dbll_get_c_addr ========
341  *  Get address of a "C" name in the specified library.
342  */
dbll_get_c_addr(struct dbll_library_obj * zl_lib,char * name,struct dbll_sym_val ** sym_val)343 bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
344 		     struct dbll_sym_val **sym_val)
345 {
346 	struct dbll_symbol *sym;
347 	char cname[MAXEXPR + 1];
348 	bool status = false;
349 
350 	DBC_REQUIRE(refs > 0);
351 	DBC_REQUIRE(zl_lib);
352 	DBC_REQUIRE(sym_val != NULL);
353 	DBC_REQUIRE(zl_lib->sym_tab != NULL);
354 	DBC_REQUIRE(name != NULL);
355 
356 	cname[0] = '_';
357 
358 	strncpy(cname + 1, name, sizeof(cname) - 2);
359 	cname[MAXEXPR] = '\0';	/* insure '\0' string termination */
360 
361 	/* Check for C name, if not found */
362 	sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
363 
364 	if (sym != NULL) {
365 		*sym_val = &sym->value;
366 		status = true;
367 	}
368 
369 	return status;
370 }
371 
372 /*
373  *  ======== dbll_get_sect ========
374  *  Get the base address and size (in bytes) of a COFF section.
375  */
dbll_get_sect(struct dbll_library_obj * lib,char * name,u32 * paddr,u32 * psize)376 int dbll_get_sect(struct dbll_library_obj *lib, char *name, u32 *paddr,
377 			 u32 *psize)
378 {
379 	u32 byte_size;
380 	bool opened_doff = false;
381 	const struct ldr_section_info *sect = NULL;
382 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
383 	int status = 0;
384 
385 	DBC_REQUIRE(refs > 0);
386 	DBC_REQUIRE(name != NULL);
387 	DBC_REQUIRE(paddr != NULL);
388 	DBC_REQUIRE(psize != NULL);
389 	DBC_REQUIRE(zl_lib);
390 
391 	/* If DOFF file is not open, we open it. */
392 	if (zl_lib != NULL) {
393 		if (zl_lib->fp == NULL) {
394 			status = dof_open(zl_lib);
395 			if (!status)
396 				opened_doff = true;
397 
398 		} else {
399 			(*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
400 							      zl_lib->pos,
401 							      SEEK_SET);
402 		}
403 	} else {
404 		status = -EFAULT;
405 	}
406 	if (!status) {
407 		byte_size = 1;
408 		if (dload_get_section_info(zl_lib->desc, name, &sect)) {
409 			*paddr = sect->load_addr;
410 			*psize = sect->size * byte_size;
411 			/* Make sure size is even for good swap */
412 			if (*psize % 2)
413 				(*psize)++;
414 
415 			/* Align size */
416 			*psize = DOFF_ALIGN(*psize);
417 		} else {
418 			status = -ENXIO;
419 		}
420 	}
421 	if (opened_doff) {
422 		dof_close(zl_lib);
423 		opened_doff = false;
424 	}
425 
426 	dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p psize: %p, "
427 		"status 0x%x\n", __func__, lib, name, paddr, psize, status);
428 
429 	return status;
430 }
431 
432 /*
433  *  ======== dbll_init ========
434  */
dbll_init(void)435 bool dbll_init(void)
436 {
437 	DBC_REQUIRE(refs >= 0);
438 
439 	if (refs == 0)
440 		gh_init();
441 
442 	refs++;
443 
444 	return true;
445 }
446 
447 /*
448  *  ======== dbll_load ========
449  */
dbll_load(struct dbll_library_obj * lib,dbll_flags flags,struct dbll_attrs * attrs,u32 * entry)450 int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
451 		     struct dbll_attrs *attrs, u32 *entry)
452 {
453 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
454 	struct dbll_tar_obj *dbzl;
455 	bool got_symbols = true;
456 	s32 err;
457 	int status = 0;
458 	bool opened_doff = false;
459 	DBC_REQUIRE(refs > 0);
460 	DBC_REQUIRE(zl_lib);
461 	DBC_REQUIRE(entry != NULL);
462 	DBC_REQUIRE(attrs != NULL);
463 
464 	/*
465 	 *  Load if not already loaded.
466 	 */
467 	if (zl_lib->load_ref == 0 || !(flags & DBLL_DYNAMIC)) {
468 		dbzl = zl_lib->target_obj;
469 		dbzl->attrs = *attrs;
470 		/* Create a hash table for symbols if not already created */
471 		if (zl_lib->sym_tab == NULL) {
472 			got_symbols = false;
473 			zl_lib->sym_tab = gh_create(MAXBUCKETS,
474 						    sizeof(struct dbll_symbol),
475 						    name_hash,
476 						    name_match, sym_delete);
477 			if (zl_lib->sym_tab == NULL)
478 				status = -ENOMEM;
479 
480 		}
481 		/*
482 		 *  Set up objects needed by the dynamic loader
483 		 */
484 		/* Stream */
485 		zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
486 		zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
487 		zl_lib->stream.lib = zl_lib;
488 		/* Symbol */
489 		zl_lib->symbol.dl_symbol.find_matching_symbol =
490 		    dbll_find_symbol;
491 		if (got_symbols) {
492 			zl_lib->symbol.dl_symbol.add_to_symbol_table =
493 			    find_in_symbol_table;
494 		} else {
495 			zl_lib->symbol.dl_symbol.add_to_symbol_table =
496 			    dbll_add_to_symbol_table;
497 		}
498 		zl_lib->symbol.dl_symbol.purge_symbol_table =
499 		    dbll_purge_symbol_table;
500 		zl_lib->symbol.dl_symbol.dload_allocate = allocate;
501 		zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
502 		zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
503 		zl_lib->symbol.lib = zl_lib;
504 		/* Allocate */
505 		zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
506 		zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
507 		zl_lib->allocate.lib = zl_lib;
508 		/* Init */
509 		zl_lib->init.dl_init.connect = connect;
510 		zl_lib->init.dl_init.readmem = read_mem;
511 		zl_lib->init.dl_init.writemem = write_mem;
512 		zl_lib->init.dl_init.fillmem = fill_mem;
513 		zl_lib->init.dl_init.execute = execute;
514 		zl_lib->init.dl_init.release = release;
515 		zl_lib->init.lib = zl_lib;
516 		/* If COFF file is not open, we open it. */
517 		if (zl_lib->fp == NULL) {
518 			status = dof_open(zl_lib);
519 			if (!status)
520 				opened_doff = true;
521 
522 		}
523 		if (!status) {
524 			zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell))
525 			    (zl_lib->fp);
526 			/* Reset file cursor */
527 			(*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
528 							      (long)0,
529 							      SEEK_SET);
530 			symbols_reloaded = true;
531 			/* The 5th argument, DLOAD_INITBSS, tells the DLL
532 			 * module to zero-init all BSS sections.  In general,
533 			 * this is not necessary and also increases load time.
534 			 * We may want to make this configurable by the user */
535 			err = dynamic_load_module(&zl_lib->stream.dl_stream,
536 						  &zl_lib->symbol.dl_symbol,
537 						  &zl_lib->allocate.dl_alloc,
538 						  &zl_lib->init.dl_init,
539 						  DLOAD_INITBSS,
540 						  &zl_lib->dload_mod_obj);
541 
542 			if (err != 0) {
543 				status = -EILSEQ;
544 			} else if (redefined_symbol) {
545 				zl_lib->load_ref++;
546 				dbll_unload(zl_lib, (struct dbll_attrs *)attrs);
547 				redefined_symbol = false;
548 				status = -EILSEQ;
549 			} else {
550 				*entry = zl_lib->entry;
551 			}
552 		}
553 	}
554 	if (!status)
555 		zl_lib->load_ref++;
556 
557 	/* Clean up DOFF resources */
558 	if (opened_doff)
559 		dof_close(zl_lib);
560 
561 	DBC_ENSURE(status || zl_lib->load_ref > 0);
562 
563 	dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
564 		__func__, lib, flags, entry, status);
565 
566 	return status;
567 }
568 
569 /*
570  *  ======== dbll_open ========
571  */
dbll_open(struct dbll_tar_obj * target,char * file,dbll_flags flags,struct dbll_library_obj ** lib_obj)572 int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
573 		     struct dbll_library_obj **lib_obj)
574 {
575 	struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
576 	struct dbll_library_obj *zl_lib = NULL;
577 	s32 err;
578 	int status = 0;
579 
580 	DBC_REQUIRE(refs > 0);
581 	DBC_REQUIRE(zl_target);
582 	DBC_REQUIRE(zl_target->attrs.fopen != NULL);
583 	DBC_REQUIRE(file != NULL);
584 	DBC_REQUIRE(lib_obj != NULL);
585 
586 	zl_lib = zl_target->head;
587 	while (zl_lib != NULL) {
588 		if (strcmp(zl_lib->file_name, file) == 0) {
589 			/* Library is already opened */
590 			zl_lib->open_ref++;
591 			break;
592 		}
593 		zl_lib = zl_lib->next;
594 	}
595 	if (zl_lib == NULL) {
596 		/* Allocate DBL library object */
597 		zl_lib = kzalloc(sizeof(struct dbll_library_obj), GFP_KERNEL);
598 		if (zl_lib == NULL) {
599 			status = -ENOMEM;
600 		} else {
601 			zl_lib->pos = 0;
602 			/* Increment ref count to allow close on failure
603 			 * later on */
604 			zl_lib->open_ref++;
605 			zl_lib->target_obj = zl_target;
606 			/* Keep a copy of the file name */
607 			zl_lib->file_name = kzalloc(strlen(file) + 1,
608 							GFP_KERNEL);
609 			if (zl_lib->file_name == NULL) {
610 				status = -ENOMEM;
611 			} else {
612 				strncpy(zl_lib->file_name, file,
613 					strlen(file) + 1);
614 			}
615 			zl_lib->sym_tab = NULL;
616 		}
617 	}
618 	/*
619 	 *  Set up objects needed by the dynamic loader
620 	 */
621 	if (status)
622 		goto func_cont;
623 
624 	/* Stream */
625 	zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
626 	zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
627 	zl_lib->stream.lib = zl_lib;
628 	/* Symbol */
629 	zl_lib->symbol.dl_symbol.add_to_symbol_table = dbll_add_to_symbol_table;
630 	zl_lib->symbol.dl_symbol.find_matching_symbol = dbll_find_symbol;
631 	zl_lib->symbol.dl_symbol.purge_symbol_table = dbll_purge_symbol_table;
632 	zl_lib->symbol.dl_symbol.dload_allocate = allocate;
633 	zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
634 	zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
635 	zl_lib->symbol.lib = zl_lib;
636 	/* Allocate */
637 	zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
638 	zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
639 	zl_lib->allocate.lib = zl_lib;
640 	/* Init */
641 	zl_lib->init.dl_init.connect = connect;
642 	zl_lib->init.dl_init.readmem = read_mem;
643 	zl_lib->init.dl_init.writemem = write_mem;
644 	zl_lib->init.dl_init.fillmem = fill_mem;
645 	zl_lib->init.dl_init.execute = execute;
646 	zl_lib->init.dl_init.release = release;
647 	zl_lib->init.lib = zl_lib;
648 	if (!status && zl_lib->fp == NULL)
649 		status = dof_open(zl_lib);
650 
651 	zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell)) (zl_lib->fp);
652 	(*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0, SEEK_SET);
653 	/* Create a hash table for symbols if flag is set */
654 	if (zl_lib->sym_tab != NULL || !(flags & DBLL_SYMB))
655 		goto func_cont;
656 
657 	zl_lib->sym_tab =
658 	    gh_create(MAXBUCKETS, sizeof(struct dbll_symbol), name_hash,
659 		      name_match, sym_delete);
660 	if (zl_lib->sym_tab == NULL) {
661 		status = -ENOMEM;
662 	} else {
663 		/* Do a fake load to get symbols - set write func to no_op */
664 		zl_lib->init.dl_init.writemem = no_op;
665 		err = dynamic_open_module(&zl_lib->stream.dl_stream,
666 					  &zl_lib->symbol.dl_symbol,
667 					  &zl_lib->allocate.dl_alloc,
668 					  &zl_lib->init.dl_init, 0,
669 					  &zl_lib->dload_mod_obj);
670 		if (err != 0) {
671 			status = -EILSEQ;
672 		} else {
673 			/* Now that we have the symbol table, we can unload */
674 			err = dynamic_unload_module(zl_lib->dload_mod_obj,
675 						    &zl_lib->symbol.dl_symbol,
676 						    &zl_lib->allocate.dl_alloc,
677 						    &zl_lib->init.dl_init);
678 			if (err != 0)
679 				status = -EILSEQ;
680 
681 			zl_lib->dload_mod_obj = NULL;
682 		}
683 	}
684 func_cont:
685 	if (!status) {
686 		if (zl_lib->open_ref == 1) {
687 			/* First time opened - insert in list */
688 			if (zl_target->head)
689 				(zl_target->head)->prev = zl_lib;
690 
691 			zl_lib->prev = NULL;
692 			zl_lib->next = zl_target->head;
693 			zl_target->head = zl_lib;
694 		}
695 		*lib_obj = (struct dbll_library_obj *)zl_lib;
696 	} else {
697 		*lib_obj = NULL;
698 		if (zl_lib != NULL)
699 			dbll_close((struct dbll_library_obj *)zl_lib);
700 
701 	}
702 	DBC_ENSURE((!status && (zl_lib->open_ref > 0) && *lib_obj)
703 				|| (status && *lib_obj == NULL));
704 
705 	dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
706 		__func__, target, file, lib_obj, status);
707 
708 	return status;
709 }
710 
711 /*
712  *  ======== dbll_read_sect ========
713  *  Get the content of a COFF section.
714  */
dbll_read_sect(struct dbll_library_obj * lib,char * name,char * buf,u32 size)715 int dbll_read_sect(struct dbll_library_obj *lib, char *name,
716 			  char *buf, u32 size)
717 {
718 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
719 	bool opened_doff = false;
720 	u32 byte_size;		/* size of bytes */
721 	u32 ul_sect_size;	/* size of section */
722 	const struct ldr_section_info *sect = NULL;
723 	int status = 0;
724 
725 	DBC_REQUIRE(refs > 0);
726 	DBC_REQUIRE(zl_lib);
727 	DBC_REQUIRE(name != NULL);
728 	DBC_REQUIRE(buf != NULL);
729 	DBC_REQUIRE(size != 0);
730 
731 	/* If DOFF file is not open, we open it. */
732 	if (zl_lib != NULL) {
733 		if (zl_lib->fp == NULL) {
734 			status = dof_open(zl_lib);
735 			if (!status)
736 				opened_doff = true;
737 
738 		} else {
739 			(*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
740 							      zl_lib->pos,
741 							      SEEK_SET);
742 		}
743 	} else {
744 		status = -EFAULT;
745 	}
746 	if (status)
747 		goto func_cont;
748 
749 	byte_size = 1;
750 	if (!dload_get_section_info(zl_lib->desc, name, &sect)) {
751 		status = -ENXIO;
752 		goto func_cont;
753 	}
754 	/*
755 	 * Ensure the supplied buffer size is sufficient to store
756 	 * the section buf to be read.
757 	 */
758 	ul_sect_size = sect->size * byte_size;
759 	/* Make sure size is even for good swap */
760 	if (ul_sect_size % 2)
761 		ul_sect_size++;
762 
763 	/* Align size */
764 	ul_sect_size = DOFF_ALIGN(ul_sect_size);
765 	if (ul_sect_size > size) {
766 		status = -EPERM;
767 	} else {
768 		if (!dload_get_section(zl_lib->desc, sect, buf))
769 			status = -EBADF;
770 
771 	}
772 func_cont:
773 	if (opened_doff) {
774 		dof_close(zl_lib);
775 		opened_doff = false;
776 	}
777 
778 	dev_dbg(bridge, "%s: lib: %p name: %s buf: %p size: 0x%x, "
779 		"status 0x%x\n", __func__, lib, name, buf, size, status);
780 	return status;
781 }
782 
783 /*
784  *  ======== dbll_unload ========
785  */
dbll_unload(struct dbll_library_obj * lib,struct dbll_attrs * attrs)786 void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs)
787 {
788 	struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
789 	s32 err = 0;
790 
791 	DBC_REQUIRE(refs > 0);
792 	DBC_REQUIRE(zl_lib);
793 	DBC_REQUIRE(zl_lib->load_ref > 0);
794 	dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
795 	zl_lib->load_ref--;
796 	/* Unload only if reference count is 0 */
797 	if (zl_lib->load_ref != 0)
798 		goto func_end;
799 
800 	zl_lib->target_obj->attrs = *attrs;
801 	if (zl_lib->dload_mod_obj) {
802 		err = dynamic_unload_module(zl_lib->dload_mod_obj,
803 					    &zl_lib->symbol.dl_symbol,
804 					    &zl_lib->allocate.dl_alloc,
805 					    &zl_lib->init.dl_init);
806 		if (err != 0)
807 			dev_dbg(bridge, "%s: failed: 0x%x\n", __func__, err);
808 	}
809 	/* remove symbols from symbol table */
810 	if (zl_lib->sym_tab != NULL) {
811 		gh_delete(zl_lib->sym_tab);
812 		zl_lib->sym_tab = NULL;
813 	}
814 	/* delete DOFF desc since it holds *lots* of host OS
815 	 * resources */
816 	dof_close(zl_lib);
817 func_end:
818 	DBC_ENSURE(zl_lib->load_ref >= 0);
819 }
820 
821 /*
822  *  ======== dof_close ========
823  */
dof_close(struct dbll_library_obj * zl_lib)824 static void dof_close(struct dbll_library_obj *zl_lib)
825 {
826 	if (zl_lib->desc) {
827 		dload_module_close(zl_lib->desc);
828 		zl_lib->desc = NULL;
829 	}
830 	/* close file */
831 	if (zl_lib->fp) {
832 		(zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
833 		zl_lib->fp = NULL;
834 	}
835 }
836 
837 /*
838  *  ======== dof_open ========
839  */
dof_open(struct dbll_library_obj * zl_lib)840 static int dof_open(struct dbll_library_obj *zl_lib)
841 {
842 	void *open = *(zl_lib->target_obj->attrs.fopen);
843 	int status = 0;
844 
845 	/* First open the file for the dynamic loader, then open COF */
846 	zl_lib->fp =
847 	    (void *)((dbll_f_open_fxn) (open)) (zl_lib->file_name, "rb");
848 
849 	/* Open DOFF module */
850 	if (zl_lib->fp && zl_lib->desc == NULL) {
851 		(*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0,
852 						      SEEK_SET);
853 		zl_lib->desc =
854 		    dload_module_open(&zl_lib->stream.dl_stream,
855 				      &zl_lib->symbol.dl_symbol);
856 		if (zl_lib->desc == NULL) {
857 			(zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
858 			zl_lib->fp = NULL;
859 			status = -EBADF;
860 		}
861 	} else {
862 		status = -EBADF;
863 	}
864 
865 	return status;
866 }
867 
868 /*
869  *  ======== name_hash ========
870  */
name_hash(void * key,u16 max_bucket)871 static u16 name_hash(void *key, u16 max_bucket)
872 {
873 	u16 ret;
874 	u16 hash;
875 	char *name = (char *)key;
876 
877 	DBC_REQUIRE(name != NULL);
878 
879 	hash = 0;
880 
881 	while (*name) {
882 		hash <<= 1;
883 		hash ^= *name++;
884 	}
885 
886 	ret = hash % max_bucket;
887 
888 	return ret;
889 }
890 
891 /*
892  *  ======== name_match ========
893  */
name_match(void * key,void * sp)894 static bool name_match(void *key, void *sp)
895 {
896 	DBC_REQUIRE(key != NULL);
897 	DBC_REQUIRE(sp != NULL);
898 
899 	if ((key != NULL) && (sp != NULL)) {
900 		if (strcmp((char *)key, ((struct dbll_symbol *)sp)->name) ==
901 		    0)
902 			return true;
903 	}
904 	return false;
905 }
906 
907 /*
908  *  ======== no_op ========
909  */
no_op(struct dynamic_loader_initialize * thisptr,void * bufr,ldr_addr locn,struct ldr_section_info * info,unsigned bytsize)910 static int no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
911 		 ldr_addr locn, struct ldr_section_info *info, unsigned bytsize)
912 {
913 	return 1;
914 }
915 
916 /*
917  *  ======== sym_delete ========
918  */
sym_delete(void * value)919 static void sym_delete(void *value)
920 {
921 	struct dbll_symbol *sp = (struct dbll_symbol *)value;
922 
923 	kfree(sp->name);
924 }
925 
926 /*
927  *  Dynamic Loader Functions
928  */
929 
930 /* dynamic_loader_stream */
931 /*
932  *  ======== dbll_read_buffer ========
933  */
dbll_read_buffer(struct dynamic_loader_stream * this,void * buffer,unsigned bufsize)934 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
935 			    unsigned bufsize)
936 {
937 	struct dbll_stream *pstream = (struct dbll_stream *)this;
938 	struct dbll_library_obj *lib;
939 	int bytes_read = 0;
940 
941 	DBC_REQUIRE(this != NULL);
942 	lib = pstream->lib;
943 	DBC_REQUIRE(lib);
944 
945 	if (lib != NULL) {
946 		bytes_read =
947 		    (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
948 						       lib->fp);
949 	}
950 	return bytes_read;
951 }
952 
953 /*
954  *  ======== dbll_set_file_posn ========
955  */
dbll_set_file_posn(struct dynamic_loader_stream * this,unsigned int pos)956 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
957 			      unsigned int pos)
958 {
959 	struct dbll_stream *pstream = (struct dbll_stream *)this;
960 	struct dbll_library_obj *lib;
961 	int status = 0;		/* Success */
962 
963 	DBC_REQUIRE(this != NULL);
964 	lib = pstream->lib;
965 	DBC_REQUIRE(lib);
966 
967 	if (lib != NULL) {
968 		status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
969 							    SEEK_SET);
970 	}
971 
972 	return status;
973 }
974 
975 /* dynamic_loader_sym */
976 
977 /*
978  *  ======== dbll_find_symbol ========
979  */
dbll_find_symbol(struct dynamic_loader_sym * this,const char * name)980 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
981 					       const char *name)
982 {
983 	struct dynload_symbol *ret_sym;
984 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
985 	struct dbll_library_obj *lib;
986 	struct dbll_sym_val *dbll_sym = NULL;
987 	bool status = false;	/* Symbol not found yet */
988 
989 	DBC_REQUIRE(this != NULL);
990 	lib = ldr_sym->lib;
991 	DBC_REQUIRE(lib);
992 
993 	if (lib != NULL) {
994 		if (lib->target_obj->attrs.sym_lookup) {
995 			/* Check current lib + base lib + dep lib +
996 			 * persistent lib */
997 			status = (*(lib->target_obj->attrs.sym_lookup))
998 			    (lib->target_obj->attrs.sym_handle,
999 			     lib->target_obj->attrs.sym_arg,
1000 			     lib->target_obj->attrs.rmm_handle, name,
1001 			     &dbll_sym);
1002 		} else {
1003 			/* Just check current lib for symbol */
1004 			status = dbll_get_addr((struct dbll_library_obj *)lib,
1005 					       (char *)name, &dbll_sym);
1006 			if (!status) {
1007 				status =
1008 				    dbll_get_c_addr((struct dbll_library_obj *)
1009 						    lib, (char *)name,
1010 						    &dbll_sym);
1011 			}
1012 		}
1013 	}
1014 
1015 	if (!status && gbl_search)
1016 		dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
1017 
1018 	DBC_ASSERT((status && (dbll_sym != NULL))
1019 		   || (!status && (dbll_sym == NULL)));
1020 
1021 	ret_sym = (struct dynload_symbol *)dbll_sym;
1022 	return ret_sym;
1023 }
1024 
1025 /*
1026  *  ======== find_in_symbol_table ========
1027  */
find_in_symbol_table(struct dynamic_loader_sym * this,const char * name,unsigned moduleid)1028 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
1029 						   *this, const char *name,
1030 						   unsigned moduleid)
1031 {
1032 	struct dynload_symbol *ret_sym;
1033 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1034 	struct dbll_library_obj *lib;
1035 	struct dbll_symbol *sym;
1036 
1037 	DBC_REQUIRE(this != NULL);
1038 	lib = ldr_sym->lib;
1039 	DBC_REQUIRE(lib);
1040 	DBC_REQUIRE(lib->sym_tab != NULL);
1041 
1042 	sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
1043 
1044 	ret_sym = (struct dynload_symbol *)&sym->value;
1045 	return ret_sym;
1046 }
1047 
1048 /*
1049  *  ======== dbll_add_to_symbol_table ========
1050  */
dbll_add_to_symbol_table(struct dynamic_loader_sym * this,const char * name,unsigned module_id)1051 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
1052 						       *this, const char *name,
1053 						       unsigned module_id)
1054 {
1055 	struct dbll_symbol *sym_ptr = NULL;
1056 	struct dbll_symbol symbol;
1057 	struct dynload_symbol *dbll_sym = NULL;
1058 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1059 	struct dbll_library_obj *lib;
1060 	struct dynload_symbol *ret;
1061 
1062 	DBC_REQUIRE(this != NULL);
1063 	DBC_REQUIRE(name);
1064 	lib = ldr_sym->lib;
1065 	DBC_REQUIRE(lib);
1066 
1067 	/* Check to see if symbol is already defined in symbol table */
1068 	if (!(lib->target_obj->attrs.base_image)) {
1069 		gbl_search = false;
1070 		dbll_sym = dbll_find_symbol(this, name);
1071 		gbl_search = true;
1072 		if (dbll_sym) {
1073 			redefined_symbol = true;
1074 			dev_dbg(bridge, "%s already defined in symbol table\n",
1075 				name);
1076 			return NULL;
1077 		}
1078 	}
1079 	/* Allocate string to copy symbol name */
1080 	symbol.name = kzalloc(strlen((char *const)name) + 1, GFP_KERNEL);
1081 	if (symbol.name == NULL)
1082 		return NULL;
1083 
1084 	if (symbol.name != NULL) {
1085 		/* Just copy name (value will be filled in by dynamic loader) */
1086 		strncpy(symbol.name, (char *const)name,
1087 			strlen((char *const)name) + 1);
1088 
1089 		/* Add symbol to symbol table */
1090 		sym_ptr =
1091 		    (struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
1092 						    (void *)&symbol);
1093 		if (sym_ptr == NULL)
1094 			kfree(symbol.name);
1095 
1096 	}
1097 	if (sym_ptr != NULL)
1098 		ret = (struct dynload_symbol *)&sym_ptr->value;
1099 	else
1100 		ret = NULL;
1101 
1102 	return ret;
1103 }
1104 
1105 /*
1106  *  ======== dbll_purge_symbol_table ========
1107  */
dbll_purge_symbol_table(struct dynamic_loader_sym * this,unsigned module_id)1108 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
1109 				    unsigned module_id)
1110 {
1111 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1112 	struct dbll_library_obj *lib;
1113 
1114 	DBC_REQUIRE(this != NULL);
1115 	lib = ldr_sym->lib;
1116 	DBC_REQUIRE(lib);
1117 
1118 	/* May not need to do anything */
1119 }
1120 
1121 /*
1122  *  ======== allocate ========
1123  */
allocate(struct dynamic_loader_sym * this,unsigned memsize)1124 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize)
1125 {
1126 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1127 	struct dbll_library_obj *lib;
1128 	void *buf;
1129 
1130 	DBC_REQUIRE(this != NULL);
1131 	lib = ldr_sym->lib;
1132 	DBC_REQUIRE(lib);
1133 
1134 	buf = kzalloc(memsize, GFP_KERNEL);
1135 
1136 	return buf;
1137 }
1138 
1139 /*
1140  *  ======== deallocate ========
1141  */
deallocate(struct dynamic_loader_sym * this,void * mem_ptr)1142 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr)
1143 {
1144 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1145 	struct dbll_library_obj *lib;
1146 
1147 	DBC_REQUIRE(this != NULL);
1148 	lib = ldr_sym->lib;
1149 	DBC_REQUIRE(lib);
1150 
1151 	kfree(mem_ptr);
1152 }
1153 
1154 /*
1155  *  ======== dbll_err_report ========
1156  */
dbll_err_report(struct dynamic_loader_sym * this,const char * errstr,va_list args)1157 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
1158 			    va_list args)
1159 {
1160 	struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1161 	struct dbll_library_obj *lib;
1162 	char temp_buf[MAXEXPR];
1163 
1164 	DBC_REQUIRE(this != NULL);
1165 	lib = ldr_sym->lib;
1166 	DBC_REQUIRE(lib);
1167 	vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
1168 	dev_dbg(bridge, "%s\n", temp_buf);
1169 }
1170 
1171 /* dynamic_loader_allocate */
1172 
1173 /*
1174  *  ======== dbll_rmm_alloc ========
1175  */
dbll_rmm_alloc(struct dynamic_loader_allocate * this,struct ldr_section_info * info,unsigned align)1176 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
1177 			  struct ldr_section_info *info, unsigned align)
1178 {
1179 	struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1180 	struct dbll_library_obj *lib;
1181 	int status = 0;
1182 	u32 mem_sect_type;
1183 	struct rmm_addr rmm_addr_obj;
1184 	s32 ret = true;
1185 	unsigned stype = DLOAD_SECTION_TYPE(info->type);
1186 	char *token = NULL;
1187 	char *sz_sec_last_token = NULL;
1188 	char *sz_last_token = NULL;
1189 	char *sz_sect_name = NULL;
1190 	char *psz_cur;
1191 	s32 token_len = 0;
1192 	s32 seg_id = -1;
1193 	s32 req = -1;
1194 	s32 count = 0;
1195 	u32 alloc_size = 0;
1196 	u32 run_addr_flag = 0;
1197 
1198 	DBC_REQUIRE(this != NULL);
1199 	lib = dbll_alloc_obj->lib;
1200 	DBC_REQUIRE(lib);
1201 
1202 	mem_sect_type =
1203 	    (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1204 						 DLOAD_BSS) ? DBLL_BSS :
1205 	    DBLL_DATA;
1206 
1207 	/* Attempt to extract the segment ID and requirement information from
1208 	   the name of the section */
1209 	DBC_REQUIRE(info->name);
1210 	token_len = strlen((char *)(info->name)) + 1;
1211 
1212 	sz_sect_name = kzalloc(token_len, GFP_KERNEL);
1213 	sz_last_token = kzalloc(token_len, GFP_KERNEL);
1214 	sz_sec_last_token = kzalloc(token_len, GFP_KERNEL);
1215 
1216 	if (sz_sect_name == NULL || sz_sec_last_token == NULL ||
1217 	    sz_last_token == NULL) {
1218 		status = -ENOMEM;
1219 		goto func_cont;
1220 	}
1221 	strncpy(sz_sect_name, (char *)(info->name), token_len);
1222 	psz_cur = sz_sect_name;
1223 	while ((token = strsep(&psz_cur, ":")) && *token != '\0') {
1224 		strncpy(sz_sec_last_token, sz_last_token,
1225 			strlen(sz_last_token) + 1);
1226 		strncpy(sz_last_token, token, strlen(token) + 1);
1227 		token = strsep(&psz_cur, ":");
1228 		count++;	/* optimizes processing */
1229 	}
1230 	/* If token is 0 or 1, and sz_sec_last_token is DYN_DARAM or DYN_SARAM,
1231 	   or DYN_EXTERNAL, then mem granularity information is present
1232 	   within the section name - only process if there are at least three
1233 	   tokens within the section name (just a minor optimization) */
1234 	if (count >= 3)
1235 		strict_strtol(sz_last_token, 10, (long *)&req);
1236 
1237 	if ((req == 0) || (req == 1)) {
1238 		if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
1239 			seg_id = 0;
1240 		} else {
1241 			if (strcmp(sz_sec_last_token, "DYN_SARAM") == 0) {
1242 				seg_id = 1;
1243 			} else {
1244 				if (strcmp(sz_sec_last_token,
1245 					   "DYN_EXTERNAL") == 0)
1246 					seg_id = 2;
1247 			}
1248 		}
1249 	}
1250 func_cont:
1251 	kfree(sz_sect_name);
1252 	sz_sect_name = NULL;
1253 	kfree(sz_last_token);
1254 	sz_last_token = NULL;
1255 	kfree(sz_sec_last_token);
1256 	sz_sec_last_token = NULL;
1257 
1258 	if (mem_sect_type == DBLL_CODE)
1259 		alloc_size = info->size + GEM_L1P_PREFETCH_SIZE;
1260 	else
1261 		alloc_size = info->size;
1262 
1263 	if (info->load_addr != info->run_addr)
1264 		run_addr_flag = 1;
1265 	/* TODO - ideally, we can pass the alignment requirement also
1266 	 * from here */
1267 	if (lib != NULL) {
1268 		status =
1269 		    (lib->target_obj->attrs.alloc) (lib->target_obj->attrs.
1270 						    rmm_handle, mem_sect_type,
1271 						    alloc_size, align,
1272 						    (u32 *) &rmm_addr_obj,
1273 						    seg_id, req, false);
1274 	}
1275 	if (status) {
1276 		ret = false;
1277 	} else {
1278 		/* RMM gives word address. Need to convert to byte address */
1279 		info->load_addr = rmm_addr_obj.addr * DSPWORDSIZE;
1280 		if (!run_addr_flag)
1281 			info->run_addr = info->load_addr;
1282 		info->context = (u32) rmm_addr_obj.segid;
1283 		dev_dbg(bridge, "%s: %s base = 0x%x len = 0x%x, "
1284 			"info->run_addr 0x%x, info->load_addr 0x%x\n",
1285 			__func__, info->name, info->load_addr / DSPWORDSIZE,
1286 			info->size / DSPWORDSIZE, info->run_addr,
1287 			info->load_addr);
1288 	}
1289 	return ret;
1290 }
1291 
1292 /*
1293  *  ======== rmm_dealloc ========
1294  */
rmm_dealloc(struct dynamic_loader_allocate * this,struct ldr_section_info * info)1295 static void rmm_dealloc(struct dynamic_loader_allocate *this,
1296 			struct ldr_section_info *info)
1297 {
1298 	struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1299 	struct dbll_library_obj *lib;
1300 	u32 segid;
1301 	int status = 0;
1302 	unsigned stype = DLOAD_SECTION_TYPE(info->type);
1303 	u32 mem_sect_type;
1304 	u32 free_size = 0;
1305 
1306 	mem_sect_type =
1307 	    (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1308 						 DLOAD_BSS) ? DBLL_BSS :
1309 	    DBLL_DATA;
1310 	DBC_REQUIRE(this != NULL);
1311 	lib = dbll_alloc_obj->lib;
1312 	DBC_REQUIRE(lib);
1313 	/* segid was set by alloc function */
1314 	segid = (u32) info->context;
1315 	if (mem_sect_type == DBLL_CODE)
1316 		free_size = info->size + GEM_L1P_PREFETCH_SIZE;
1317 	else
1318 		free_size = info->size;
1319 	if (lib != NULL) {
1320 		status =
1321 		    (lib->target_obj->attrs.free) (lib->target_obj->attrs.
1322 						   sym_handle, segid,
1323 						   info->load_addr /
1324 						   DSPWORDSIZE, free_size,
1325 						   false);
1326 	}
1327 }
1328 
1329 /* dynamic_loader_initialize */
1330 /*
1331  *  ======== connect ========
1332  */
connect(struct dynamic_loader_initialize * this)1333 static int connect(struct dynamic_loader_initialize *this)
1334 {
1335 	return true;
1336 }
1337 
1338 /*
1339  *  ======== read_mem ========
1340  *  This function does not need to be implemented.
1341  */
read_mem(struct dynamic_loader_initialize * this,void * buf,ldr_addr addr,struct ldr_section_info * info,unsigned nbytes)1342 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
1343 		    ldr_addr addr, struct ldr_section_info *info,
1344 		    unsigned nbytes)
1345 {
1346 	struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1347 	struct dbll_library_obj *lib;
1348 	int bytes_read = 0;
1349 
1350 	DBC_REQUIRE(this != NULL);
1351 	lib = init_obj->lib;
1352 	DBC_REQUIRE(lib);
1353 	/* Need bridge_brd_read function */
1354 	return bytes_read;
1355 }
1356 
1357 /*
1358  *  ======== write_mem ========
1359  */
write_mem(struct dynamic_loader_initialize * this,void * buf,ldr_addr addr,struct ldr_section_info * info,unsigned bytes)1360 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
1361 		     ldr_addr addr, struct ldr_section_info *info,
1362 		     unsigned bytes)
1363 {
1364 	struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1365 	struct dbll_library_obj *lib;
1366 	struct dbll_tar_obj *target_obj;
1367 	struct dbll_sect_info sect_info;
1368 	u32 mem_sect_type;
1369 	bool ret = true;
1370 
1371 	DBC_REQUIRE(this != NULL);
1372 	lib = init_obj->lib;
1373 	if (!lib)
1374 		return false;
1375 
1376 	target_obj = lib->target_obj;
1377 
1378 	mem_sect_type =
1379 	    (DLOAD_SECTION_TYPE(info->type) ==
1380 	     DLOAD_TEXT) ? DBLL_CODE : DBLL_DATA;
1381 	if (target_obj && target_obj->attrs.write) {
1382 		ret =
1383 		    (*target_obj->attrs.write) (target_obj->attrs.input_params,
1384 						addr, buf, bytes,
1385 						mem_sect_type);
1386 
1387 		if (target_obj->attrs.log_write) {
1388 			sect_info.name = info->name;
1389 			sect_info.sect_run_addr = info->run_addr;
1390 			sect_info.sect_load_addr = info->load_addr;
1391 			sect_info.size = info->size;
1392 			sect_info.type = mem_sect_type;
1393 			/* Pass the information about what we've written to
1394 			 * another module */
1395 			(*target_obj->attrs.log_write) (target_obj->attrs.
1396 							log_write_handle,
1397 							&sect_info, addr,
1398 							bytes);
1399 		}
1400 	}
1401 	return ret;
1402 }
1403 
1404 /*
1405  *  ======== fill_mem ========
1406  *  Fill bytes of memory at a given address with a given value by
1407  *  writing from a buffer containing the given value.  Write in
1408  *  sets of MAXEXPR (128) bytes to avoid large stack buffer issues.
1409  */
fill_mem(struct dynamic_loader_initialize * this,ldr_addr addr,struct ldr_section_info * info,unsigned bytes,unsigned val)1410 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
1411 		    struct ldr_section_info *info, unsigned bytes, unsigned val)
1412 {
1413 	bool ret = true;
1414 	char *pbuf;
1415 	struct dbll_library_obj *lib;
1416 	struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1417 
1418 	DBC_REQUIRE(this != NULL);
1419 	lib = init_obj->lib;
1420 	pbuf = NULL;
1421 	/* Pass the NULL pointer to write_mem to get the start address of Shared
1422 	   memory. This is a trick to just get the start address, there is no
1423 	   writing taking place with this Writemem
1424 	 */
1425 	if ((lib->target_obj->attrs.write) != (dbll_write_fxn) no_op)
1426 		write_mem(this, &pbuf, addr, info, 0);
1427 	if (pbuf)
1428 		memset(pbuf, val, bytes);
1429 
1430 	return ret;
1431 }
1432 
1433 /*
1434  *  ======== execute ========
1435  */
execute(struct dynamic_loader_initialize * this,ldr_addr start)1436 static int execute(struct dynamic_loader_initialize *this, ldr_addr start)
1437 {
1438 	struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1439 	struct dbll_library_obj *lib;
1440 	bool ret = true;
1441 
1442 	DBC_REQUIRE(this != NULL);
1443 	lib = init_obj->lib;
1444 	DBC_REQUIRE(lib);
1445 	/* Save entry point */
1446 	if (lib != NULL)
1447 		lib->entry = (u32) start;
1448 
1449 	return ret;
1450 }
1451 
1452 /*
1453  *  ======== release ========
1454  */
release(struct dynamic_loader_initialize * this)1455 static void release(struct dynamic_loader_initialize *this)
1456 {
1457 }
1458 
1459 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1460 /**
1461  *  find_symbol_context - Basic symbol context structure
1462  * @address:		Symbol Address
1463  * @offset_range:		Offset range where the search for the DSP symbol
1464  *			started.
1465  * @cur_best_offset:	Best offset to start looking for the DSP symbol
1466  * @sym_addr:		Address of the DSP symbol
1467  * @name:		Symbol name
1468  *
1469  */
1470 struct find_symbol_context {
1471 	/* input */
1472 	u32 address;
1473 	u32 offset_range;
1474 	/* state */
1475 	u32 cur_best_offset;
1476 	/* output */
1477 	u32 sym_addr;
1478 	char name[120];
1479 };
1480 
1481 /**
1482  * find_symbol_callback() - Validates symbol address and copies the symbol name
1483  *			to the user data.
1484  * @elem:		dsp library context
1485  * @user_data:		Find symbol context
1486  *
1487  */
find_symbol_callback(void * elem,void * user_data)1488 void find_symbol_callback(void *elem, void *user_data)
1489 {
1490 	struct dbll_symbol *symbol = elem;
1491 	struct find_symbol_context *context = user_data;
1492 	u32 symbol_addr = symbol->value.value;
1493 	u32 offset = context->address - symbol_addr;
1494 
1495 	/*
1496 	 * Address given should be greater than symbol address,
1497 	 * symbol address should be  within specified range
1498 	 * and the offset should be better than previous one
1499 	 */
1500 	if (context->address >= symbol_addr && symbol_addr < (u32)-1 &&
1501 		offset < context->cur_best_offset) {
1502 		context->cur_best_offset = offset;
1503 		context->sym_addr = symbol_addr;
1504 		strncpy(context->name, symbol->name, sizeof(context->name));
1505 	}
1506 
1507 	return;
1508 }
1509 
1510 /**
1511  * dbll_find_dsp_symbol() - This function retrieves the dsp symbol from the dsp binary.
1512  * @zl_lib:		DSP binary obj library pointer
1513  * @address:		Given address to find the dsp symbol
1514  * @offset_range:		offset range to look for dsp symbol
1515  * @sym_addr_output:	Symbol Output address
1516  * @name_output:		String with the dsp symbol
1517  *
1518  * 	This function retrieves the dsp symbol from the dsp binary.
1519  */
dbll_find_dsp_symbol(struct dbll_library_obj * zl_lib,u32 address,u32 offset_range,u32 * sym_addr_output,char * name_output)1520 bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
1521 				u32 offset_range, u32 *sym_addr_output,
1522 				char *name_output)
1523 {
1524 	bool status = false;
1525 	struct find_symbol_context context;
1526 
1527 	context.address = address;
1528 	context.offset_range = offset_range;
1529 	context.cur_best_offset = offset_range;
1530 	context.sym_addr = 0;
1531 	context.name[0] = '\0';
1532 
1533 	gh_iterate(zl_lib->sym_tab, find_symbol_callback, &context);
1534 
1535 	if (context.name[0]) {
1536 		status = true;
1537 		strcpy(name_output, context.name);
1538 		*sym_addr_output = context.sym_addr;
1539 	}
1540 
1541 	return status;
1542 }
1543 #endif
1544