Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dbll.c
Go to the documentation of this file.
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 */
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 {
69 };
70 
71 /*
72  * ======== ldr_symbol ========
73  */
74 struct ldr_symbol {
77 };
78 
79 /*
80  * ======== dbll_alloc ========
81  */
82 struct dbll_alloc {
85 };
86 
87 /*
88  * ======== dbll_init_obj ========
89  */
90 struct dbll_init_obj {
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  */
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 */
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 */
125 };
126 
127 /*
128  * ======== dbll_symbol ========
129  */
130 struct dbll_symbol {
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,
175  unsigned bytes);
176 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
390 bool dbll_init(void)
391 {
392  /* do nothing */
393 
394  return true;
395 }
396 
397 /*
398  * ======== dbll_load ========
399  */
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,
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 =
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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) ==
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  */
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  */
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  */
1336 static void release(struct dynamic_loader_initialize *this)
1337 {
1338 }
1339 
1340 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1341 
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 
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 
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