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, §)) {
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, §)) {
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 §_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