4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
16 #include <linux/types.h>
18 /* ----------------------------------- Host OS */
19 #include <dspbridge/host_os.h>
21 /* ----------------------------------- DSP/BIOS Bridge */
22 #include <dspbridge/dbdefs.h>
24 #include <dspbridge/gh.h>
26 /* ----------------------------------- OS Adaptation Layer */
28 /* Dynamic loader library interface */
29 #include <dspbridge/dynamic_loader.h>
30 #include <dspbridge/getsection.h>
32 /* ----------------------------------- This */
33 #include <dspbridge/dbll.h>
34 #include <dspbridge/rmm.h>
36 /* Max buffer length */
39 #define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
42 * ======== struct dbll_tar_obj* ========
43 * A target may have one or more libraries of symbols/code/data loaded
44 * onto it, where a library is simply the symbols/code/data contained
48 * ======== dbll_tar_obj ========
51 struct dbll_attrs attrs;
52 struct dbll_library_obj *head; /* List of all opened libraries */
56 * The following 4 typedefs are "super classes" of the dynamic loader
57 * library types used in dynamic loader functions (dynamic_loader.h).
60 * ======== dbll_stream ========
61 * Contains dynamic_loader_stream
64 struct dynamic_loader_stream dl_stream;
65 struct dbll_library_obj *lib;
69 * ======== ldr_symbol ========
72 struct dynamic_loader_sym dl_symbol;
73 struct dbll_library_obj *lib;
77 * ======== dbll_alloc ========
80 struct dynamic_loader_allocate dl_alloc;
81 struct dbll_library_obj *lib;
85 * ======== dbll_init_obj ========
87 struct dbll_init_obj {
88 struct dynamic_loader_initialize dl_init;
89 struct dbll_library_obj *lib;
93 * ======== DBLL_Library ========
94 * A library handle is returned by DBLL_Open() and is passed to dbll_load()
95 * to load symbols/code/data, and to dbll_unload(), to remove the
96 * symbols/code/data loaded by dbll_load().
100 * ======== dbll_library_obj ========
102 struct dbll_library_obj {
103 struct dbll_library_obj *next; /* Next library in target's list */
104 struct dbll_library_obj *prev; /* Previous in the list */
105 struct dbll_tar_obj *target_obj; /* target for this library */
107 /* Objects needed by dynamic loader */
108 struct dbll_stream stream;
109 struct ldr_symbol symbol;
110 struct dbll_alloc allocate;
111 struct dbll_init_obj init;
114 char *file_name; /* COFF file name */
115 void *fp; /* Opaque file handle */
116 u32 entry; /* Entry point */
117 void *desc; /* desc of DOFF file loaded */
118 u32 open_ref; /* Number of times opened */
119 u32 load_ref; /* Number of times loaded */
120 struct gh_t_hash_tab *sym_tab; /* Hash table of symbols */
125 * ======== dbll_symbol ========
128 struct dbll_sym_val value;
132 static void dof_close(struct dbll_library_obj *zl_lib);
133 static int dof_open(struct dbll_library_obj *zl_lib);
134 static s32 no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
135 ldr_addr locn, struct ldr_section_info *info,
139 * Functions called by dynamic loader
142 /* dynamic_loader_stream */
143 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
145 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
147 /* dynamic_loader_sym */
148 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
150 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
151 *this, const char *name,
153 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
154 *this, const char *name,
156 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
158 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize);
159 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr);
160 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
162 /* dynamic_loader_allocate */
163 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
164 struct ldr_section_info *info, unsigned align);
165 static void rmm_dealloc(struct dynamic_loader_allocate *this,
166 struct ldr_section_info *info);
168 /* dynamic_loader_initialize */
169 static int connect(struct dynamic_loader_initialize *this);
170 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
171 ldr_addr addr, struct ldr_section_info *info,
173 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
174 ldr_addr addr, struct ldr_section_info *info,
176 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
177 struct ldr_section_info *info, unsigned bytes,
179 static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
180 static void release(struct dynamic_loader_initialize *this);
182 /* symbol table hash functions */
183 static u32 name_hash(const void *key);
184 static bool name_match(const void *key, const void *sp);
185 static void sym_delete(void *value);
187 /* Symbol Redefinition */
188 static int redefined_symbol;
189 static int gbl_search = 1;
192 * ======== dbll_close ========
194 void dbll_close(struct dbll_library_obj *zl_lib)
196 struct dbll_tar_obj *zl_target;
198 zl_target = zl_lib->target_obj;
200 if (zl_lib->open_ref == 0) {
201 /* Remove library from list */
202 if (zl_target->head == zl_lib)
203 zl_target->head = zl_lib->next;
206 (zl_lib->prev)->next = zl_lib->next;
209 (zl_lib->next)->prev = zl_lib->prev;
211 /* Free DOF resources */
213 kfree(zl_lib->file_name);
215 /* remove symbols from symbol table */
217 gh_delete(zl_lib->sym_tab);
219 /* remove the library object itself */
226 * ======== dbll_create ========
228 int dbll_create(struct dbll_tar_obj **target_obj,
229 struct dbll_attrs *pattrs)
231 struct dbll_tar_obj *pzl_target;
234 /* Allocate DBL target object */
235 pzl_target = kzalloc(sizeof(struct dbll_tar_obj), GFP_KERNEL);
236 if (target_obj != NULL) {
237 if (pzl_target == NULL) {
241 pzl_target->attrs = *pattrs;
242 *target_obj = (struct dbll_tar_obj *)pzl_target;
250 * ======== dbll_delete ========
252 void dbll_delete(struct dbll_tar_obj *target)
254 struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
261 * ======== dbll_exit ========
262 * Discontinue usage of DBL module.
270 * ======== dbll_get_addr ========
271 * Get address of name in the specified library.
273 bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
274 struct dbll_sym_val **sym_val)
276 struct dbll_symbol *sym;
278 sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
282 *sym_val = &sym->value;
284 dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p\n",
285 __func__, zl_lib, name, sym_val);
290 * ======== dbll_get_attrs ========
291 * Retrieve the attributes of the target.
293 void dbll_get_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
295 struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
297 if ((pattrs != NULL) && (zl_target != NULL))
298 *pattrs = zl_target->attrs;
303 * ======== dbll_get_c_addr ========
304 * Get address of a "C" name in the specified library.
306 bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
307 struct dbll_sym_val **sym_val)
309 struct dbll_symbol *sym;
310 char cname[MAXEXPR + 1];
314 strncpy(cname + 1, name, sizeof(cname) - 2);
315 cname[MAXEXPR] = '\0'; /* insure '\0' string termination */
317 /* Check for C name, if not found */
318 sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
322 *sym_val = &sym->value;
328 * ======== dbll_get_sect ========
329 * Get the base address and size (in bytes) of a COFF section.
331 int dbll_get_sect(struct dbll_library_obj *lib, char *name, u32 *paddr,
335 bool opened_doff = false;
336 const struct ldr_section_info *sect = NULL;
337 struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
340 /* If DOFF file is not open, we open it. */
341 if (zl_lib != NULL) {
342 if (zl_lib->fp == NULL) {
343 status = dof_open(zl_lib);
348 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
357 if (dload_get_section_info(zl_lib->desc, name, §)) {
358 *paddr = sect->load_addr;
359 *psize = sect->size * byte_size;
360 /* Make sure size is even for good swap */
365 *psize = DOFF_ALIGN(*psize);
375 dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p psize: %p, status 0x%x\n",
376 __func__, lib, name, paddr, psize, status);
382 * ======== dbll_init ========
392 * ======== dbll_load ========
394 int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
395 struct dbll_attrs *attrs, u32 *entry)
397 struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
398 struct dbll_tar_obj *dbzl;
399 bool got_symbols = true;
402 bool opened_doff = false;
405 * Load if not already loaded.
407 if (zl_lib->load_ref == 0 || !(flags & DBLL_DYNAMIC)) {
408 dbzl = zl_lib->target_obj;
409 dbzl->attrs = *attrs;
410 /* Create a hash table for symbols if not already created */
411 if (zl_lib->sym_tab == NULL) {
413 zl_lib->sym_tab = gh_create(sizeof(struct dbll_symbol),
415 name_match, sym_delete);
416 if (IS_ERR(zl_lib->sym_tab)) {
417 status = PTR_ERR(zl_lib->sym_tab);
418 zl_lib->sym_tab = NULL;
423 * Set up objects needed by the dynamic loader
426 zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
427 zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
428 zl_lib->stream.lib = zl_lib;
430 zl_lib->symbol.dl_symbol.find_matching_symbol =
433 zl_lib->symbol.dl_symbol.add_to_symbol_table =
434 find_in_symbol_table;
436 zl_lib->symbol.dl_symbol.add_to_symbol_table =
437 dbll_add_to_symbol_table;
439 zl_lib->symbol.dl_symbol.purge_symbol_table =
440 dbll_purge_symbol_table;
441 zl_lib->symbol.dl_symbol.dload_allocate = allocate;
442 zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
443 zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
444 zl_lib->symbol.lib = zl_lib;
446 zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
447 zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
448 zl_lib->allocate.lib = zl_lib;
450 zl_lib->init.dl_init.connect = connect;
451 zl_lib->init.dl_init.readmem = read_mem;
452 zl_lib->init.dl_init.writemem = write_mem;
453 zl_lib->init.dl_init.fillmem = fill_mem;
454 zl_lib->init.dl_init.execute = execute;
455 zl_lib->init.dl_init.release = release;
456 zl_lib->init.lib = zl_lib;
457 /* If COFF file is not open, we open it. */
458 if (zl_lib->fp == NULL) {
459 status = dof_open(zl_lib);
465 zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell))
467 /* Reset file cursor */
468 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
471 symbols_reloaded = true;
472 /* The 5th argument, DLOAD_INITBSS, tells the DLL
473 * module to zero-init all BSS sections. In general,
474 * this is not necessary and also increases load time.
475 * We may want to make this configurable by the user */
476 err = dynamic_load_module(&zl_lib->stream.dl_stream,
477 &zl_lib->symbol.dl_symbol,
478 &zl_lib->allocate.dl_alloc,
479 &zl_lib->init.dl_init,
481 &zl_lib->dload_mod_obj);
485 } else if (redefined_symbol) {
487 dbll_unload(zl_lib, (struct dbll_attrs *)attrs);
488 redefined_symbol = false;
491 *entry = zl_lib->entry;
498 /* Clean up DOFF resources */
502 dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
503 __func__, lib, flags, entry, status);
509 * ======== dbll_open ========
511 int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
512 struct dbll_library_obj **lib_obj)
514 struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
515 struct dbll_library_obj *zl_lib = NULL;
519 zl_lib = zl_target->head;
520 while (zl_lib != NULL) {
521 if (strcmp(zl_lib->file_name, file) == 0) {
522 /* Library is already opened */
526 zl_lib = zl_lib->next;
528 if (zl_lib == NULL) {
529 /* Allocate DBL library object */
530 zl_lib = kzalloc(sizeof(struct dbll_library_obj), GFP_KERNEL);
531 if (zl_lib == NULL) {
535 /* Increment ref count to allow close on failure
538 zl_lib->target_obj = zl_target;
539 /* Keep a copy of the file name */
540 zl_lib->file_name = kzalloc(strlen(file) + 1,
542 if (zl_lib->file_name == NULL) {
545 strncpy(zl_lib->file_name, file,
548 zl_lib->sym_tab = NULL;
552 * Set up objects needed by the dynamic loader
558 zl_lib->stream.dl_stream.read_buffer = dbll_read_buffer;
559 zl_lib->stream.dl_stream.set_file_posn = dbll_set_file_posn;
560 zl_lib->stream.lib = zl_lib;
562 zl_lib->symbol.dl_symbol.add_to_symbol_table = dbll_add_to_symbol_table;
563 zl_lib->symbol.dl_symbol.find_matching_symbol = dbll_find_symbol;
564 zl_lib->symbol.dl_symbol.purge_symbol_table = dbll_purge_symbol_table;
565 zl_lib->symbol.dl_symbol.dload_allocate = allocate;
566 zl_lib->symbol.dl_symbol.dload_deallocate = deallocate;
567 zl_lib->symbol.dl_symbol.error_report = dbll_err_report;
568 zl_lib->symbol.lib = zl_lib;
570 zl_lib->allocate.dl_alloc.dload_allocate = dbll_rmm_alloc;
571 zl_lib->allocate.dl_alloc.dload_deallocate = rmm_dealloc;
572 zl_lib->allocate.lib = zl_lib;
574 zl_lib->init.dl_init.connect = connect;
575 zl_lib->init.dl_init.readmem = read_mem;
576 zl_lib->init.dl_init.writemem = write_mem;
577 zl_lib->init.dl_init.fillmem = fill_mem;
578 zl_lib->init.dl_init.execute = execute;
579 zl_lib->init.dl_init.release = release;
580 zl_lib->init.lib = zl_lib;
581 if (!status && zl_lib->fp == NULL)
582 status = dof_open(zl_lib);
584 zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell)) (zl_lib->fp);
585 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0, SEEK_SET);
586 /* Create a hash table for symbols if flag is set */
587 if (zl_lib->sym_tab != NULL || !(flags & DBLL_SYMB))
591 gh_create(sizeof(struct dbll_symbol), name_hash, name_match,
593 if (IS_ERR(zl_lib->sym_tab)) {
594 status = PTR_ERR(zl_lib->sym_tab);
595 zl_lib->sym_tab = NULL;
597 /* Do a fake load to get symbols - set write func to no_op */
598 zl_lib->init.dl_init.writemem = no_op;
599 err = dynamic_open_module(&zl_lib->stream.dl_stream,
600 &zl_lib->symbol.dl_symbol,
601 &zl_lib->allocate.dl_alloc,
602 &zl_lib->init.dl_init, 0,
603 &zl_lib->dload_mod_obj);
607 /* Now that we have the symbol table, we can unload */
608 err = dynamic_unload_module(zl_lib->dload_mod_obj,
609 &zl_lib->symbol.dl_symbol,
610 &zl_lib->allocate.dl_alloc,
611 &zl_lib->init.dl_init);
615 zl_lib->dload_mod_obj = NULL;
620 if (zl_lib->open_ref == 1) {
621 /* First time opened - insert in list */
623 (zl_target->head)->prev = zl_lib;
626 zl_lib->next = zl_target->head;
627 zl_target->head = zl_lib;
629 *lib_obj = (struct dbll_library_obj *)zl_lib;
633 dbll_close((struct dbll_library_obj *)zl_lib);
637 dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
638 __func__, target, file, lib_obj, status);
644 * ======== dbll_read_sect ========
645 * Get the content of a COFF section.
647 int dbll_read_sect(struct dbll_library_obj *lib, char *name,
650 struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
651 bool opened_doff = false;
652 u32 byte_size; /* size of bytes */
653 u32 ul_sect_size; /* size of section */
654 const struct ldr_section_info *sect = NULL;
657 /* If DOFF file is not open, we open it. */
658 if (zl_lib != NULL) {
659 if (zl_lib->fp == NULL) {
660 status = dof_open(zl_lib);
665 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
676 if (!dload_get_section_info(zl_lib->desc, name, §)) {
681 * Ensure the supplied buffer size is sufficient to store
682 * the section buf to be read.
684 ul_sect_size = sect->size * byte_size;
685 /* Make sure size is even for good swap */
686 if (ul_sect_size % 2)
690 ul_sect_size = DOFF_ALIGN(ul_sect_size);
691 if (ul_sect_size > size) {
694 if (!dload_get_section(zl_lib->desc, sect, buf))
704 dev_dbg(bridge, "%s: lib: %p name: %s buf: %p size: 0x%x, status 0x%x\n",
705 __func__, lib, name, buf, size, status);
710 * ======== dbll_unload ========
712 void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs)
714 struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
717 dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
719 /* Unload only if reference count is 0 */
720 if (zl_lib->load_ref != 0)
723 zl_lib->target_obj->attrs = *attrs;
724 if (zl_lib->dload_mod_obj) {
725 err = dynamic_unload_module(zl_lib->dload_mod_obj,
726 &zl_lib->symbol.dl_symbol,
727 &zl_lib->allocate.dl_alloc,
728 &zl_lib->init.dl_init);
730 dev_dbg(bridge, "%s: failed: 0x%x\n", __func__, err);
732 /* remove symbols from symbol table */
733 if (zl_lib->sym_tab != NULL) {
734 gh_delete(zl_lib->sym_tab);
735 zl_lib->sym_tab = NULL;
737 /* delete DOFF desc since it holds *lots* of host OS
743 * ======== dof_close ========
745 static void dof_close(struct dbll_library_obj *zl_lib)
748 dload_module_close(zl_lib->desc);
753 (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
759 * ======== dof_open ========
761 static int dof_open(struct dbll_library_obj *zl_lib)
763 void *open = *(zl_lib->target_obj->attrs.fopen);
766 /* First open the file for the dynamic loader, then open COF */
768 (void *)((dbll_f_open_fxn) (open)) (zl_lib->file_name, "rb");
770 /* Open DOFF module */
771 if (zl_lib->fp && zl_lib->desc == NULL) {
772 (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp, (long)0,
775 dload_module_open(&zl_lib->stream.dl_stream,
776 &zl_lib->symbol.dl_symbol);
777 if (zl_lib->desc == NULL) {
778 (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
790 * ======== name_hash ========
792 static u32 name_hash(const void *key)
795 const char *name = key;
808 * ======== name_match ========
810 static bool name_match(const void *key, const void *sp)
812 if ((key != NULL) && (sp != NULL)) {
813 if (strcmp(key, ((struct dbll_symbol *)sp)->name) == 0)
820 * ======== no_op ========
822 static int no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
823 ldr_addr locn, struct ldr_section_info *info, unsigned bytsize)
829 * ======== sym_delete ========
831 static void sym_delete(void *value)
833 struct dbll_symbol *sp = (struct dbll_symbol *)value;
839 * Dynamic Loader Functions
842 /* dynamic_loader_stream */
844 * ======== dbll_read_buffer ========
846 static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
849 struct dbll_stream *pstream = (struct dbll_stream *)this;
850 struct dbll_library_obj *lib;
856 (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
863 * ======== dbll_set_file_posn ========
865 static int dbll_set_file_posn(struct dynamic_loader_stream *this,
868 struct dbll_stream *pstream = (struct dbll_stream *)this;
869 struct dbll_library_obj *lib;
870 int status = 0; /* Success */
874 status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
881 /* dynamic_loader_sym */
884 * ======== dbll_find_symbol ========
886 static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
889 struct dynload_symbol *ret_sym;
890 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
891 struct dbll_library_obj *lib;
892 struct dbll_sym_val *dbll_sym = NULL;
893 bool status = false; /* Symbol not found yet */
897 if (lib->target_obj->attrs.sym_lookup) {
898 /* Check current lib + base lib + dep lib +
900 status = (*(lib->target_obj->attrs.sym_lookup))
901 (lib->target_obj->attrs.sym_handle,
902 lib->target_obj->attrs.sym_arg,
903 lib->target_obj->attrs.rmm_handle, name,
906 /* Just check current lib for symbol */
907 status = dbll_get_addr((struct dbll_library_obj *)lib,
908 (char *)name, &dbll_sym);
910 status = dbll_get_c_addr(
911 (struct dbll_library_obj *)
918 if (!status && gbl_search)
919 dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
921 ret_sym = (struct dynload_symbol *)dbll_sym;
926 * ======== find_in_symbol_table ========
928 static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
929 *this, const char *name,
932 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
933 struct dbll_library_obj *lib;
934 struct dbll_symbol *sym;
937 sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
942 return (struct dynload_symbol *)&sym->value;
946 * ======== dbll_add_to_symbol_table ========
948 static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
949 *this, const char *name,
952 struct dbll_symbol *sym_ptr = NULL;
953 struct dbll_symbol symbol;
954 struct dynload_symbol *dbll_sym = NULL;
955 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
956 struct dbll_library_obj *lib;
957 struct dynload_symbol *ret;
961 /* Check to see if symbol is already defined in symbol table */
962 if (!(lib->target_obj->attrs.base_image)) {
964 dbll_sym = dbll_find_symbol(this, name);
967 redefined_symbol = true;
968 dev_dbg(bridge, "%s already defined in symbol table\n",
973 /* Allocate string to copy symbol name */
974 symbol.name = kzalloc(strlen((char *const)name) + 1, GFP_KERNEL);
975 if (symbol.name == NULL)
978 if (symbol.name != NULL) {
979 /* Just copy name (value will be filled in by dynamic loader) */
980 strncpy(symbol.name, (char *const)name,
981 strlen((char *const)name) + 1);
983 /* Add symbol to symbol table */
985 (struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
987 if (IS_ERR(sym_ptr)) {
994 ret = (struct dynload_symbol *)&sym_ptr->value;
1002 * ======== dbll_purge_symbol_table ========
1004 static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
1007 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1008 struct dbll_library_obj *lib;
1011 /* May not need to do anything */
1015 * ======== allocate ========
1017 static void *allocate(struct dynamic_loader_sym *this, unsigned memsize)
1019 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1020 struct dbll_library_obj *lib;
1025 buf = kzalloc(memsize, GFP_KERNEL);
1031 * ======== deallocate ========
1033 static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr)
1035 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1036 struct dbll_library_obj *lib;
1044 * ======== dbll_err_report ========
1046 static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
1049 struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1050 struct dbll_library_obj *lib;
1051 char temp_buf[MAXEXPR];
1054 vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
1055 dev_dbg(bridge, "%s\n", temp_buf);
1058 /* dynamic_loader_allocate */
1061 * ======== dbll_rmm_alloc ========
1063 static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
1064 struct ldr_section_info *info, unsigned align)
1066 struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1067 struct dbll_library_obj *lib;
1070 struct rmm_addr rmm_addr_obj;
1072 unsigned stype = DLOAD_SECTION_TYPE(info->type);
1074 char *sz_sec_last_token = NULL;
1075 char *sz_last_token = NULL;
1076 char *sz_sect_name = NULL;
1083 u32 run_addr_flag = 0;
1085 lib = dbll_alloc_obj->lib;
1088 (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1089 DLOAD_BSS) ? DBLL_BSS :
1092 /* Attempt to extract the segment ID and requirement information from
1093 the name of the section */
1094 token_len = strlen((char *)(info->name)) + 1;
1096 sz_sect_name = kzalloc(token_len, GFP_KERNEL);
1097 sz_last_token = kzalloc(token_len, GFP_KERNEL);
1098 sz_sec_last_token = kzalloc(token_len, GFP_KERNEL);
1100 if (sz_sect_name == NULL || sz_sec_last_token == NULL ||
1101 sz_last_token == NULL) {
1105 strncpy(sz_sect_name, (char *)(info->name), token_len);
1106 psz_cur = sz_sect_name;
1107 while ((token = strsep(&psz_cur, ":")) && *token != '\0') {
1108 strncpy(sz_sec_last_token, sz_last_token,
1109 strlen(sz_last_token) + 1);
1110 strncpy(sz_last_token, token, strlen(token) + 1);
1111 token = strsep(&psz_cur, ":");
1112 count++; /* optimizes processing */
1114 /* If token is 0 or 1, and sz_sec_last_token is DYN_DARAM or DYN_SARAM,
1115 or DYN_EXTERNAL, then mem granularity information is present
1116 within the section name - only process if there are at least three
1117 tokens within the section name (just a minor optimization) */
1119 status = kstrtos32(sz_last_token, 10, &req);
1124 if ((req == 0) || (req == 1)) {
1125 if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
1128 if (strcmp(sz_sec_last_token, "DYN_SARAM") == 0) {
1131 if (strcmp(sz_sec_last_token,
1132 "DYN_EXTERNAL") == 0)
1138 kfree(sz_sect_name);
1139 sz_sect_name = NULL;
1140 kfree(sz_last_token);
1141 sz_last_token = NULL;
1142 kfree(sz_sec_last_token);
1143 sz_sec_last_token = NULL;
1145 if (mem_sect_type == DBLL_CODE)
1146 alloc_size = info->size + GEM_L1P_PREFETCH_SIZE;
1148 alloc_size = info->size;
1150 if (info->load_addr != info->run_addr)
1152 /* TODO - ideally, we can pass the alignment requirement also
1156 (lib->target_obj->attrs.alloc) (lib->target_obj->attrs.
1157 rmm_handle, mem_sect_type,
1159 (u32 *) &rmm_addr_obj,
1160 seg_id, req, false);
1165 /* RMM gives word address. Need to convert to byte address */
1166 info->load_addr = rmm_addr_obj.addr * DSPWORDSIZE;
1168 info->run_addr = info->load_addr;
1169 info->context = (u32) rmm_addr_obj.segid;
1170 dev_dbg(bridge, "%s: %s base = 0x%x len = 0x%x, info->run_addr 0x%x, info->load_addr 0x%x\n",
1171 __func__, info->name, info->load_addr / DSPWORDSIZE,
1172 info->size / DSPWORDSIZE, info->run_addr,
1179 * ======== rmm_dealloc ========
1181 static void rmm_dealloc(struct dynamic_loader_allocate *this,
1182 struct ldr_section_info *info)
1184 struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1185 struct dbll_library_obj *lib;
1188 unsigned stype = DLOAD_SECTION_TYPE(info->type);
1193 (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1194 DLOAD_BSS) ? DBLL_BSS :
1196 lib = dbll_alloc_obj->lib;
1197 /* segid was set by alloc function */
1198 segid = (u32) info->context;
1199 if (mem_sect_type == DBLL_CODE)
1200 free_size = info->size + GEM_L1P_PREFETCH_SIZE;
1202 free_size = info->size;
1205 (lib->target_obj->attrs.free) (lib->target_obj->attrs.
1208 DSPWORDSIZE, free_size,
1213 /* dynamic_loader_initialize */
1215 * ======== connect ========
1217 static int connect(struct dynamic_loader_initialize *this)
1223 * ======== read_mem ========
1224 * This function does not need to be implemented.
1226 static int read_mem(struct dynamic_loader_initialize *this, void *buf,
1227 ldr_addr addr, struct ldr_section_info *info,
1230 struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1231 struct dbll_library_obj *lib;
1234 lib = init_obj->lib;
1235 /* Need bridge_brd_read function */
1240 * ======== write_mem ========
1242 static int write_mem(struct dynamic_loader_initialize *this, void *buf,
1243 ldr_addr addr, struct ldr_section_info *info,
1246 struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1247 struct dbll_library_obj *lib;
1248 struct dbll_tar_obj *target_obj;
1249 struct dbll_sect_info sect_info;
1253 lib = init_obj->lib;
1257 target_obj = lib->target_obj;
1260 (DLOAD_SECTION_TYPE(info->type) ==
1261 DLOAD_TEXT) ? DBLL_CODE : DBLL_DATA;
1262 if (target_obj && target_obj->attrs.write) {
1264 (*target_obj->attrs.write) (target_obj->attrs.input_params,
1268 if (target_obj->attrs.log_write) {
1269 sect_info.name = info->name;
1270 sect_info.sect_run_addr = info->run_addr;
1271 sect_info.sect_load_addr = info->load_addr;
1272 sect_info.size = info->size;
1273 sect_info.type = mem_sect_type;
1274 /* Pass the information about what we've written to
1276 (*target_obj->attrs.log_write) (target_obj->attrs.
1286 * ======== fill_mem ========
1287 * Fill bytes of memory at a given address with a given value by
1288 * writing from a buffer containing the given value. Write in
1289 * sets of MAXEXPR (128) bytes to avoid large stack buffer issues.
1291 static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
1292 struct ldr_section_info *info, unsigned bytes, unsigned val)
1296 struct dbll_library_obj *lib;
1297 struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1299 lib = init_obj->lib;
1301 /* Pass the NULL pointer to write_mem to get the start address of Shared
1302 memory. This is a trick to just get the start address, there is no
1303 writing taking place with this Writemem
1305 if ((lib->target_obj->attrs.write) != (dbll_write_fxn) no_op)
1306 write_mem(this, &pbuf, addr, info, 0);
1308 memset(pbuf, val, bytes);
1314 * ======== execute ========
1316 static int execute(struct dynamic_loader_initialize *this, ldr_addr start)
1318 struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1319 struct dbll_library_obj *lib;
1322 lib = init_obj->lib;
1323 /* Save entry point */
1325 lib->entry = (u32) start;
1331 * ======== release ========
1333 static void release(struct dynamic_loader_initialize *this)
1337 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1339 * find_symbol_context - Basic symbol context structure
1340 * @address: Symbol Address
1341 * @offset_range: Offset range where the search for the DSP symbol
1343 * @cur_best_offset: Best offset to start looking for the DSP symbol
1344 * @sym_addr: Address of the DSP symbol
1345 * @name: Symbol name
1348 struct find_symbol_context {
1353 u32 cur_best_offset;
1360 * find_symbol_callback() - Validates symbol address and copies the symbol name
1362 * @elem: dsp library context
1363 * @user_data: Find symbol context
1366 void find_symbol_callback(void *elem, void *user_data)
1368 struct dbll_symbol *symbol = elem;
1369 struct find_symbol_context *context = user_data;
1370 u32 symbol_addr = symbol->value.value;
1371 u32 offset = context->address - symbol_addr;
1374 * Address given should be greater than symbol address,
1375 * symbol address should be within specified range
1376 * and the offset should be better than previous one
1378 if (context->address >= symbol_addr && symbol_addr < (u32)-1 &&
1379 offset < context->cur_best_offset) {
1380 context->cur_best_offset = offset;
1381 context->sym_addr = symbol_addr;
1382 strlcpy(context->name, symbol->name, sizeof(context->name));
1389 * dbll_find_dsp_symbol() - This function retrieves the dsp symbol from the dsp binary.
1390 * @zl_lib: DSP binary obj library pointer
1391 * @address: Given address to find the dsp symbol
1392 * @offset_range: offset range to look for dsp symbol
1393 * @sym_addr_output: Symbol Output address
1394 * @name_output: String with the dsp symbol
1396 * This function retrieves the dsp symbol from the dsp binary.
1398 bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
1399 u32 offset_range, u32 *sym_addr_output,
1402 bool status = false;
1403 struct find_symbol_context context;
1405 context.address = address;
1406 context.offset_range = offset_range;
1407 context.cur_best_offset = offset_range;
1408 context.sym_addr = 0;
1409 context.name[0] = '\0';
1411 gh_iterate(zl_lib->sym_tab, find_symbol_callback, &context);
1413 if (context.name[0]) {
1415 strcpy(name_output, context.name);
1416 *sym_addr_output = context.sym_addr;