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