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 /* ----------------------------------- Trace & Debug */
25 #include <dspbridge/dbc.h>
26 #include <dspbridge/gh.h>
28 /* ----------------------------------- OS Adaptation Layer */
30 /* Dynamic loader library interface */
31 #include <dspbridge/dynamic_loader.h>
32 #include <dspbridge/getsection.h>
34 /* ----------------------------------- This */
35 #include <dspbridge/dbll.h>
36 #include <dspbridge/rmm.h>
38 /* Number of buckets for symbol hash table */
39 #define MAXBUCKETS 211
41 /* Max buffer length */
44 #define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
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
53 * ======== dbll_tar_obj ========
56 struct dbll_attrs attrs
;
57 struct dbll_library_obj
*head
; /* List of all opened libraries */
61 * The following 4 typedefs are "super classes" of the dynamic loader
62 * library types used in dynamic loader functions (dynamic_loader.h).
65 * ======== dbll_stream ========
66 * Contains dynamic_loader_stream
69 struct dynamic_loader_stream dl_stream
;
70 struct dbll_library_obj
*lib
;
74 * ======== ldr_symbol ========
77 struct dynamic_loader_sym dl_symbol
;
78 struct dbll_library_obj
*lib
;
82 * ======== dbll_alloc ========
85 struct dynamic_loader_allocate dl_alloc
;
86 struct dbll_library_obj
*lib
;
90 * ======== dbll_init_obj ========
92 struct dbll_init_obj
{
93 struct dynamic_loader_initialize dl_init
;
94 struct dbll_library_obj
*lib
;
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().
105 * ======== dbll_library_obj ========
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 */
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
;
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 */
130 * ======== dbll_symbol ========
133 struct dbll_sym_val value
;
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
,
144 * Functions called by dynamic loader
147 /* dynamic_loader_stream */
148 static int dbll_read_buffer(struct dynamic_loader_stream
*this, void *buffer
,
150 static int dbll_set_file_posn(struct dynamic_loader_stream
*this,
152 /* dynamic_loader_sym */
153 static struct dynload_symbol
*dbll_find_symbol(struct dynamic_loader_sym
*this,
155 static struct dynload_symbol
*dbll_add_to_symbol_table(struct dynamic_loader_sym
156 *this, const char *name
,
158 static struct dynload_symbol
*find_in_symbol_table(struct dynamic_loader_sym
159 *this, const char *name
,
161 static void dbll_purge_symbol_table(struct dynamic_loader_sym
*this,
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
,
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
);
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
,
178 static int write_mem(struct dynamic_loader_initialize
*this, void *buf
,
179 ldr_addr addr
, struct ldr_section_info
*info
,
181 static int fill_mem(struct dynamic_loader_initialize
*this, ldr_addr addr
,
182 struct ldr_section_info
*info
, unsigned bytes
,
184 static int execute(struct dynamic_loader_initialize
*this, ldr_addr start
);
185 static void release(struct dynamic_loader_initialize
*this);
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
);
192 static u32 refs
; /* module reference count */
194 /* Symbol Redefinition */
195 static int redefined_symbol
;
196 static int gbl_search
= 1;
199 * ======== dbll_close ========
201 void dbll_close(struct dbll_library_obj
*zl_lib
)
203 struct dbll_tar_obj
*zl_target
;
205 DBC_REQUIRE(refs
> 0);
207 DBC_REQUIRE(zl_lib
->open_ref
> 0);
208 zl_target
= zl_lib
->target_obj
;
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
;
216 (zl_lib
->prev
)->next
= zl_lib
->next
;
219 (zl_lib
->next
)->prev
= zl_lib
->prev
;
221 /* Free DOF resources */
223 kfree(zl_lib
->file_name
);
225 /* remove symbols from symbol table */
227 gh_delete(zl_lib
->sym_tab
);
229 /* remove the library object itself */
236 * ======== dbll_create ========
238 int dbll_create(struct dbll_tar_obj
**target_obj
,
239 struct dbll_attrs
*pattrs
)
241 struct dbll_tar_obj
*pzl_target
;
244 DBC_REQUIRE(refs
> 0);
245 DBC_REQUIRE(pattrs
!= NULL
);
246 DBC_REQUIRE(target_obj
!= NULL
);
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
) {
255 pzl_target
->attrs
= *pattrs
;
256 *target_obj
= (struct dbll_tar_obj
*)pzl_target
;
258 DBC_ENSURE((!status
&& *target_obj
) ||
259 (status
&& *target_obj
== NULL
));
266 * ======== dbll_delete ========
268 void dbll_delete(struct dbll_tar_obj
*target
)
270 struct dbll_tar_obj
*zl_target
= (struct dbll_tar_obj
*)target
;
272 DBC_REQUIRE(refs
> 0);
273 DBC_REQUIRE(zl_target
);
280 * ======== dbll_exit ========
281 * Discontinue usage of DBL module.
285 DBC_REQUIRE(refs
> 0);
292 DBC_ENSURE(refs
>= 0);
296 * ======== dbll_get_addr ========
297 * Get address of name in the specified library.
299 bool dbll_get_addr(struct dbll_library_obj
*zl_lib
, char *name
,
300 struct dbll_sym_val
**sym_val
)
302 struct dbll_symbol
*sym
;
305 DBC_REQUIRE(refs
> 0);
307 DBC_REQUIRE(name
!= NULL
);
308 DBC_REQUIRE(sym_val
!= NULL
);
309 DBC_REQUIRE(zl_lib
->sym_tab
!= NULL
);
311 sym
= (struct dbll_symbol
*)gh_find(zl_lib
->sym_tab
, name
);
313 *sym_val
= &sym
->value
;
317 dev_dbg(bridge
, "%s: lib: %p name: %s paddr: %p, status 0x%x\n",
318 __func__
, zl_lib
, name
, sym_val
, status
);
323 * ======== dbll_get_attrs ========
324 * Retrieve the attributes of the target.
326 void dbll_get_attrs(struct dbll_tar_obj
*target
, struct dbll_attrs
*pattrs
)
328 struct dbll_tar_obj
*zl_target
= (struct dbll_tar_obj
*)target
;
330 DBC_REQUIRE(refs
> 0);
331 DBC_REQUIRE(zl_target
);
332 DBC_REQUIRE(pattrs
!= NULL
);
334 if ((pattrs
!= NULL
) && (zl_target
!= NULL
))
335 *pattrs
= zl_target
->attrs
;
340 * ======== dbll_get_c_addr ========
341 * Get address of a "C" name in the specified library.
343 bool dbll_get_c_addr(struct dbll_library_obj
*zl_lib
, char *name
,
344 struct dbll_sym_val
**sym_val
)
346 struct dbll_symbol
*sym
;
347 char cname
[MAXEXPR
+ 1];
350 DBC_REQUIRE(refs
> 0);
352 DBC_REQUIRE(sym_val
!= NULL
);
353 DBC_REQUIRE(zl_lib
->sym_tab
!= NULL
);
354 DBC_REQUIRE(name
!= NULL
);
358 strncpy(cname
+ 1, name
, sizeof(cname
) - 2);
359 cname
[MAXEXPR
] = '\0'; /* insure '\0' string termination */
361 /* Check for C name, if not found */
362 sym
= (struct dbll_symbol
*)gh_find(zl_lib
->sym_tab
, cname
);
365 *sym_val
= &sym
->value
;
373 * ======== dbll_get_sect ========
374 * Get the base address and size (in bytes) of a COFF section.
376 int dbll_get_sect(struct dbll_library_obj
*lib
, char *name
, u32
*paddr
,
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
;
385 DBC_REQUIRE(refs
> 0);
386 DBC_REQUIRE(name
!= NULL
);
387 DBC_REQUIRE(paddr
!= NULL
);
388 DBC_REQUIRE(psize
!= NULL
);
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
);
399 (*(zl_lib
->target_obj
->attrs
.fseek
)) (zl_lib
->fp
,
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 */
416 *psize
= DOFF_ALIGN(*psize
);
426 dev_dbg(bridge
, "%s: lib: %p name: %s paddr: %p psize: %p, "
427 "status 0x%x\n", __func__
, lib
, name
, paddr
, psize
, status
);
433 * ======== dbll_init ========
437 DBC_REQUIRE(refs
>= 0);
448 * ======== dbll_load ========
450 int dbll_load(struct dbll_library_obj
*lib
, dbll_flags flags
,
451 struct dbll_attrs
*attrs
, u32
*entry
)
453 struct dbll_library_obj
*zl_lib
= (struct dbll_library_obj
*)lib
;
454 struct dbll_tar_obj
*dbzl
;
455 bool got_symbols
= true;
458 bool opened_doff
= false;
459 DBC_REQUIRE(refs
> 0);
461 DBC_REQUIRE(entry
!= NULL
);
462 DBC_REQUIRE(attrs
!= NULL
);
465 * Load if not already loaded.
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
) {
473 zl_lib
->sym_tab
= gh_create(MAXBUCKETS
,
474 sizeof(struct dbll_symbol
),
476 name_match
, sym_delete
);
477 if (zl_lib
->sym_tab
== NULL
)
482 * Set up objects needed by the dynamic loader
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
;
489 zl_lib
->symbol
.dl_symbol
.find_matching_symbol
=
492 zl_lib
->symbol
.dl_symbol
.add_to_symbol_table
=
493 find_in_symbol_table
;
495 zl_lib
->symbol
.dl_symbol
.add_to_symbol_table
=
496 dbll_add_to_symbol_table
;
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
;
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
;
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
);
524 zl_lib
->pos
= (*(zl_lib
->target_obj
->attrs
.ftell
))
526 /* Reset file cursor */
527 (*(zl_lib
->target_obj
->attrs
.fseek
)) (zl_lib
->fp
,
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
,
540 &zl_lib
->dload_mod_obj
);
544 } else if (redefined_symbol
) {
546 dbll_unload(zl_lib
, (struct dbll_attrs
*)attrs
);
547 redefined_symbol
= false;
550 *entry
= zl_lib
->entry
;
557 /* Clean up DOFF resources */
561 DBC_ENSURE(status
|| zl_lib
->load_ref
> 0);
563 dev_dbg(bridge
, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
564 __func__
, lib
, flags
, entry
, status
);
570 * ======== dbll_open ========
572 int dbll_open(struct dbll_tar_obj
*target
, char *file
, dbll_flags flags
,
573 struct dbll_library_obj
**lib_obj
)
575 struct dbll_tar_obj
*zl_target
= (struct dbll_tar_obj
*)target
;
576 struct dbll_library_obj
*zl_lib
= NULL
;
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
);
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 */
593 zl_lib
= zl_lib
->next
;
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
) {
602 /* Increment ref count to allow close on failure
605 zl_lib
->target_obj
= zl_target
;
606 /* Keep a copy of the file name */
607 zl_lib
->file_name
= kzalloc(strlen(file
) + 1,
609 if (zl_lib
->file_name
== NULL
) {
612 strncpy(zl_lib
->file_name
, file
,
615 zl_lib
->sym_tab
= NULL
;
619 * Set up objects needed by the dynamic loader
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
;
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
;
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
;
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
);
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
))
658 gh_create(MAXBUCKETS
, sizeof(struct dbll_symbol
), name_hash
,
659 name_match
, sym_delete
);
660 if (zl_lib
->sym_tab
== NULL
) {
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
);
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
);
681 zl_lib
->dload_mod_obj
= NULL
;
686 if (zl_lib
->open_ref
== 1) {
687 /* First time opened - insert in list */
689 (zl_target
->head
)->prev
= zl_lib
;
692 zl_lib
->next
= zl_target
->head
;
693 zl_target
->head
= zl_lib
;
695 *lib_obj
= (struct dbll_library_obj
*)zl_lib
;
699 dbll_close((struct dbll_library_obj
*)zl_lib
);
702 DBC_ENSURE((!status
&& (zl_lib
->open_ref
> 0) && *lib_obj
)
703 || (status
&& *lib_obj
== NULL
));
705 dev_dbg(bridge
, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
706 __func__
, target
, file
, lib_obj
, status
);
712 * ======== dbll_read_sect ========
713 * Get the content of a COFF section.
715 int dbll_read_sect(struct dbll_library_obj
*lib
, char *name
,
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
;
725 DBC_REQUIRE(refs
> 0);
727 DBC_REQUIRE(name
!= NULL
);
728 DBC_REQUIRE(buf
!= NULL
);
729 DBC_REQUIRE(size
!= 0);
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
);
739 (*(zl_lib
->target_obj
->attrs
.fseek
)) (zl_lib
->fp
,
750 if (!dload_get_section_info(zl_lib
->desc
, name
, §
)) {
755 * Ensure the supplied buffer size is sufficient to store
756 * the section buf to be read.
758 ul_sect_size
= sect
->size
* byte_size
;
759 /* Make sure size is even for good swap */
760 if (ul_sect_size
% 2)
764 ul_sect_size
= DOFF_ALIGN(ul_sect_size
);
765 if (ul_sect_size
> size
) {
768 if (!dload_get_section(zl_lib
->desc
, sect
, buf
))
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
);
784 * ======== dbll_unload ========
786 void dbll_unload(struct dbll_library_obj
*lib
, struct dbll_attrs
*attrs
)
788 struct dbll_library_obj
*zl_lib
= (struct dbll_library_obj
*)lib
;
791 DBC_REQUIRE(refs
> 0);
793 DBC_REQUIRE(zl_lib
->load_ref
> 0);
794 dev_dbg(bridge
, "%s: lib: %p\n", __func__
, lib
);
796 /* Unload only if reference count is 0 */
797 if (zl_lib
->load_ref
!= 0)
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
);
807 dev_dbg(bridge
, "%s: failed: 0x%x\n", __func__
, err
);
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
;
814 /* delete DOFF desc since it holds *lots* of host OS
818 DBC_ENSURE(zl_lib
->load_ref
>= 0);
822 * ======== dof_close ========
824 static void dof_close(struct dbll_library_obj
*zl_lib
)
827 dload_module_close(zl_lib
->desc
);
832 (zl_lib
->target_obj
->attrs
.fclose
) (zl_lib
->fp
);
838 * ======== dof_open ========
840 static int dof_open(struct dbll_library_obj
*zl_lib
)
842 void *open
= *(zl_lib
->target_obj
->attrs
.fopen
);
845 /* First open the file for the dynamic loader, then open COF */
847 (void *)((dbll_f_open_fxn
) (open
)) (zl_lib
->file_name
, "rb");
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,
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
);
869 * ======== name_hash ========
871 static u16
name_hash(void *key
, u16 max_bucket
)
875 char *name
= (char *)key
;
877 DBC_REQUIRE(name
!= NULL
);
886 ret
= hash
% max_bucket
;
892 * ======== name_match ========
894 static bool name_match(void *key
, void *sp
)
896 DBC_REQUIRE(key
!= NULL
);
897 DBC_REQUIRE(sp
!= NULL
);
899 if ((key
!= NULL
) && (sp
!= NULL
)) {
900 if (strcmp((char *)key
, ((struct dbll_symbol
*)sp
)->name
) ==
908 * ======== no_op ========
910 static int no_op(struct dynamic_loader_initialize
*thisptr
, void *bufr
,
911 ldr_addr locn
, struct ldr_section_info
*info
, unsigned bytsize
)
917 * ======== sym_delete ========
919 static void sym_delete(void *value
)
921 struct dbll_symbol
*sp
= (struct dbll_symbol
*)value
;
927 * Dynamic Loader Functions
930 /* dynamic_loader_stream */
932 * ======== dbll_read_buffer ========
934 static int dbll_read_buffer(struct dynamic_loader_stream
*this, void *buffer
,
937 struct dbll_stream
*pstream
= (struct dbll_stream
*)this;
938 struct dbll_library_obj
*lib
;
941 DBC_REQUIRE(this != NULL
);
947 (*(lib
->target_obj
->attrs
.fread
)) (buffer
, 1, bufsize
,
954 * ======== dbll_set_file_posn ========
956 static int dbll_set_file_posn(struct dynamic_loader_stream
*this,
959 struct dbll_stream
*pstream
= (struct dbll_stream
*)this;
960 struct dbll_library_obj
*lib
;
961 int status
= 0; /* Success */
963 DBC_REQUIRE(this != NULL
);
968 status
= (*(lib
->target_obj
->attrs
.fseek
)) (lib
->fp
, (long)pos
,
975 /* dynamic_loader_sym */
978 * ======== dbll_find_symbol ========
980 static struct dynload_symbol
*dbll_find_symbol(struct dynamic_loader_sym
*this,
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 */
989 DBC_REQUIRE(this != NULL
);
994 if (lib
->target_obj
->attrs
.sym_lookup
) {
995 /* Check current lib + base lib + dep 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
,
1003 /* Just check current lib for symbol */
1004 status
= dbll_get_addr((struct dbll_library_obj
*)lib
,
1005 (char *)name
, &dbll_sym
);
1008 dbll_get_c_addr((struct dbll_library_obj
*)
1015 if (!status
&& gbl_search
)
1016 dev_dbg(bridge
, "%s: Symbol not found: %s\n", __func__
, name
);
1018 DBC_ASSERT((status
&& (dbll_sym
!= NULL
))
1019 || (!status
&& (dbll_sym
== NULL
)));
1021 ret_sym
= (struct dynload_symbol
*)dbll_sym
;
1026 * ======== find_in_symbol_table ========
1028 static struct dynload_symbol
*find_in_symbol_table(struct dynamic_loader_sym
1029 *this, const char *name
,
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
;
1037 DBC_REQUIRE(this != NULL
);
1040 DBC_REQUIRE(lib
->sym_tab
!= NULL
);
1042 sym
= (struct dbll_symbol
*)gh_find(lib
->sym_tab
, (char *)name
);
1044 ret_sym
= (struct dynload_symbol
*)&sym
->value
;
1049 * ======== dbll_add_to_symbol_table ========
1051 static struct dynload_symbol
*dbll_add_to_symbol_table(struct dynamic_loader_sym
1052 *this, const char *name
,
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
;
1062 DBC_REQUIRE(this != NULL
);
1067 /* Check to see if symbol is already defined in symbol table */
1068 if (!(lib
->target_obj
->attrs
.base_image
)) {
1070 dbll_sym
= dbll_find_symbol(this, name
);
1073 redefined_symbol
= true;
1074 dev_dbg(bridge
, "%s already defined in symbol table\n",
1079 /* Allocate string to copy symbol name */
1080 symbol
.name
= kzalloc(strlen((char *const)name
) + 1, GFP_KERNEL
);
1081 if (symbol
.name
== NULL
)
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);
1089 /* Add symbol to symbol table */
1091 (struct dbll_symbol
*)gh_insert(lib
->sym_tab
, (void *)name
,
1093 if (sym_ptr
== NULL
)
1097 if (sym_ptr
!= NULL
)
1098 ret
= (struct dynload_symbol
*)&sym_ptr
->value
;
1106 * ======== dbll_purge_symbol_table ========
1108 static void dbll_purge_symbol_table(struct dynamic_loader_sym
*this,
1111 struct ldr_symbol
*ldr_sym
= (struct ldr_symbol
*)this;
1112 struct dbll_library_obj
*lib
;
1114 DBC_REQUIRE(this != NULL
);
1118 /* May not need to do anything */
1122 * ======== allocate ========
1124 static void *allocate(struct dynamic_loader_sym
*this, unsigned memsize
)
1126 struct ldr_symbol
*ldr_sym
= (struct ldr_symbol
*)this;
1127 struct dbll_library_obj
*lib
;
1130 DBC_REQUIRE(this != NULL
);
1134 buf
= kzalloc(memsize
, GFP_KERNEL
);
1140 * ======== deallocate ========
1142 static void deallocate(struct dynamic_loader_sym
*this, void *mem_ptr
)
1144 struct ldr_symbol
*ldr_sym
= (struct ldr_symbol
*)this;
1145 struct dbll_library_obj
*lib
;
1147 DBC_REQUIRE(this != NULL
);
1155 * ======== dbll_err_report ========
1157 static void dbll_err_report(struct dynamic_loader_sym
*this, const char *errstr
,
1160 struct ldr_symbol
*ldr_sym
= (struct ldr_symbol
*)this;
1161 struct dbll_library_obj
*lib
;
1162 char temp_buf
[MAXEXPR
];
1164 DBC_REQUIRE(this != NULL
);
1167 vsnprintf((char *)temp_buf
, MAXEXPR
, (char *)errstr
, args
);
1168 dev_dbg(bridge
, "%s\n", temp_buf
);
1171 /* dynamic_loader_allocate */
1174 * ======== dbll_rmm_alloc ========
1176 static int dbll_rmm_alloc(struct dynamic_loader_allocate
*this,
1177 struct ldr_section_info
*info
, unsigned align
)
1179 struct dbll_alloc
*dbll_alloc_obj
= (struct dbll_alloc
*)this;
1180 struct dbll_library_obj
*lib
;
1183 struct rmm_addr rmm_addr_obj
;
1185 unsigned stype
= DLOAD_SECTION_TYPE(info
->type
);
1187 char *sz_sec_last_token
= NULL
;
1188 char *sz_last_token
= NULL
;
1189 char *sz_sect_name
= NULL
;
1196 u32 run_addr_flag
= 0;
1198 DBC_REQUIRE(this != NULL
);
1199 lib
= dbll_alloc_obj
->lib
;
1203 (stype
== DLOAD_TEXT
) ? DBLL_CODE
: (stype
==
1204 DLOAD_BSS
) ? DBLL_BSS
:
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;
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
);
1216 if (sz_sect_name
== NULL
|| sz_sec_last_token
== NULL
||
1217 sz_last_token
== NULL
) {
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 */
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) */
1235 strict_strtol(sz_last_token
, 10, (long *)&req
);
1237 if ((req
== 0) || (req
== 1)) {
1238 if (strcmp(sz_sec_last_token
, "DYN_DARAM") == 0) {
1241 if (strcmp(sz_sec_last_token
, "DYN_SARAM") == 0) {
1244 if (strcmp(sz_sec_last_token
,
1245 "DYN_EXTERNAL") == 0)
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
;
1258 if (mem_sect_type
== DBLL_CODE
)
1259 alloc_size
= info
->size
+ GEM_L1P_PREFETCH_SIZE
;
1261 alloc_size
= info
->size
;
1263 if (info
->load_addr
!= info
->run_addr
)
1265 /* TODO - ideally, we can pass the alignment requirement also
1269 (lib
->target_obj
->attrs
.alloc
) (lib
->target_obj
->attrs
.
1270 rmm_handle
, mem_sect_type
,
1272 (u32
*) &rmm_addr_obj
,
1273 seg_id
, req
, false);
1278 /* RMM gives word address. Need to convert to byte address */
1279 info
->load_addr
= rmm_addr_obj
.addr
* DSPWORDSIZE
;
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
,
1293 * ======== rmm_dealloc ========
1295 static void rmm_dealloc(struct dynamic_loader_allocate
*this,
1296 struct ldr_section_info
*info
)
1298 struct dbll_alloc
*dbll_alloc_obj
= (struct dbll_alloc
*)this;
1299 struct dbll_library_obj
*lib
;
1302 unsigned stype
= DLOAD_SECTION_TYPE(info
->type
);
1307 (stype
== DLOAD_TEXT
) ? DBLL_CODE
: (stype
==
1308 DLOAD_BSS
) ? DBLL_BSS
:
1310 DBC_REQUIRE(this != NULL
);
1311 lib
= dbll_alloc_obj
->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
;
1318 free_size
= info
->size
;
1321 (lib
->target_obj
->attrs
.free
) (lib
->target_obj
->attrs
.
1324 DSPWORDSIZE
, free_size
,
1329 /* dynamic_loader_initialize */
1331 * ======== connect ========
1333 static int connect(struct dynamic_loader_initialize
*this)
1339 * ======== read_mem ========
1340 * This function does not need to be implemented.
1342 static int read_mem(struct dynamic_loader_initialize
*this, void *buf
,
1343 ldr_addr addr
, struct ldr_section_info
*info
,
1346 struct dbll_init_obj
*init_obj
= (struct dbll_init_obj
*)this;
1347 struct dbll_library_obj
*lib
;
1350 DBC_REQUIRE(this != NULL
);
1351 lib
= init_obj
->lib
;
1353 /* Need bridge_brd_read function */
1358 * ======== write_mem ========
1360 static int write_mem(struct dynamic_loader_initialize
*this, void *buf
,
1361 ldr_addr addr
, struct ldr_section_info
*info
,
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
;
1371 DBC_REQUIRE(this != NULL
);
1372 lib
= init_obj
->lib
;
1376 target_obj
= lib
->target_obj
;
1379 (DLOAD_SECTION_TYPE(info
->type
) ==
1380 DLOAD_TEXT
) ? DBLL_CODE
: DBLL_DATA
;
1381 if (target_obj
&& target_obj
->attrs
.write
) {
1383 (*target_obj
->attrs
.write
) (target_obj
->attrs
.input_params
,
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
1395 (*target_obj
->attrs
.log_write
) (target_obj
->attrs
.
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.
1410 static int fill_mem(struct dynamic_loader_initialize
*this, ldr_addr addr
,
1411 struct ldr_section_info
*info
, unsigned bytes
, unsigned val
)
1415 struct dbll_library_obj
*lib
;
1416 struct dbll_init_obj
*init_obj
= (struct dbll_init_obj
*)this;
1418 DBC_REQUIRE(this != NULL
);
1419 lib
= init_obj
->lib
;
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
1425 if ((lib
->target_obj
->attrs
.write
) != (dbll_write_fxn
) no_op
)
1426 write_mem(this, &pbuf
, addr
, info
, 0);
1428 memset(pbuf
, val
, bytes
);
1434 * ======== execute ========
1436 static int execute(struct dynamic_loader_initialize
*this, ldr_addr start
)
1438 struct dbll_init_obj
*init_obj
= (struct dbll_init_obj
*)this;
1439 struct dbll_library_obj
*lib
;
1442 DBC_REQUIRE(this != NULL
);
1443 lib
= init_obj
->lib
;
1445 /* Save entry point */
1447 lib
->entry
= (u32
) start
;
1453 * ======== release ========
1455 static void release(struct dynamic_loader_initialize
*this)
1459 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1461 * find_symbol_context - Basic symbol context structure
1462 * @address: Symbol Address
1463 * @offset_range: Offset range where the search for the DSP symbol
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
1470 struct find_symbol_context
{
1475 u32 cur_best_offset
;
1482 * find_symbol_callback() - Validates symbol address and copies the symbol name
1484 * @elem: dsp library context
1485 * @user_data: Find symbol context
1488 void find_symbol_callback(void *elem
, void *user_data
)
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
;
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
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
));
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
1518 * This function retrieves the dsp symbol from the dsp binary.
1520 bool dbll_find_dsp_symbol(struct dbll_library_obj
*zl_lib
, u32 address
,
1521 u32 offset_range
, u32
*sym_addr_output
,
1524 bool status
= false;
1525 struct find_symbol_context context
;
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';
1533 gh_iterate(zl_lib
->sym_tab
, find_symbol_callback
, &context
);
1535 if (context
.name
[0]) {
1537 strcpy(name_output
, context
.name
);
1538 *sym_addr_output
= context
.sym_addr
;