linux/drivers/staging/tidspbridge/pmgr/dbll.c
<<
>>
Prefs
   1/*
   2 * dbll.c
   3 *
   4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
   5 *
   6 * Copyright (C) 2005-2006 Texas Instruments, Inc.
   7 *
   8 * This package is free software;  you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  15 */
  16#include <linux/types.h>
  17
  18/*  ----------------------------------- Host OS */
  19#include <dspbridge/host_os.h>
  20
  21/*  ----------------------------------- DSP/BIOS Bridge */
  22#include <dspbridge/dbdefs.h>
  23
  24#include <dspbridge/gh.h>
  25
  26/*  ----------------------------------- OS Adaptation Layer */
  27
  28/* Dynamic loader library interface */
  29#include <dspbridge/dynamic_loader.h>
  30#include <dspbridge/getsection.h>
  31
  32/*  ----------------------------------- This */
  33#include <dspbridge/dbll.h>
  34#include <dspbridge/rmm.h>
  35
  36/* Max buffer length */
  37#define MAXEXPR 128
  38
  39#define DOFF_ALIGN(x) (((x) + 3) & ~3UL)
  40
  41/*
  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
  45 *  in a DOFF file.
  46 */
  47/*
  48 *  ======== dbll_tar_obj ========
  49 */
  50struct dbll_tar_obj {
  51        struct dbll_attrs attrs;
  52        struct dbll_library_obj *head;  /* List of all opened libraries */
  53};
  54
  55/*
  56 *  The following 4 typedefs are "super classes" of the dynamic loader
  57 *  library types used in dynamic loader functions (dynamic_loader.h).
  58 */
  59/*
  60 *  ======== dbll_stream ========
  61 *  Contains dynamic_loader_stream
  62 */
  63struct dbll_stream {
  64        struct dynamic_loader_stream dl_stream;
  65        struct dbll_library_obj *lib;
  66};
  67
  68/*
  69 *  ======== ldr_symbol ========
  70 */
  71struct ldr_symbol {
  72        struct dynamic_loader_sym dl_symbol;
  73        struct dbll_library_obj *lib;
  74};
  75
  76/*
  77 *  ======== dbll_alloc ========
  78 */
  79struct dbll_alloc {
  80        struct dynamic_loader_allocate dl_alloc;
  81        struct dbll_library_obj *lib;
  82};
  83
  84/*
  85 *  ======== dbll_init_obj ========
  86 */
  87struct dbll_init_obj {
  88        struct dynamic_loader_initialize dl_init;
  89        struct dbll_library_obj *lib;
  90};
  91
  92/*
  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().
  97 */
  98
  99/*
 100 *  ======== dbll_library_obj ========
 101 */
 102struct 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 */
 106
 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;
 112        void *dload_mod_obj;
 113
 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 */
 121        u32 pos;
 122};
 123
 124/*
 125 *  ======== dbll_symbol ========
 126 */
 127struct dbll_symbol {
 128        struct dbll_sym_val value;
 129        char *name;
 130};
 131
 132static void dof_close(struct dbll_library_obj *zl_lib);
 133static int dof_open(struct dbll_library_obj *zl_lib);
 134static s32 no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
 135                 ldr_addr locn, struct ldr_section_info *info,
 136                 unsigned bytsize);
 137
 138/*
 139 *  Functions called by dynamic loader
 140 *
 141 */
 142/* dynamic_loader_stream */
 143static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
 144                            unsigned bufsize);
 145static int dbll_set_file_posn(struct dynamic_loader_stream *this,
 146                              unsigned int pos);
 147/* dynamic_loader_sym */
 148static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
 149                                               const char *name);
 150static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
 151                                                       *this, const char *name,
 152                                                       unsigned module_id);
 153static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
 154                                                   *this, const char *name,
 155                                                   unsigned moduleid);
 156static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
 157                                    unsigned module_id);
 158static void *allocate(struct dynamic_loader_sym *this, unsigned memsize);
 159static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr);
 160static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
 161                            va_list args);
 162/* dynamic_loader_allocate */
 163static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
 164                          struct ldr_section_info *info, unsigned align);
 165static void rmm_dealloc(struct dynamic_loader_allocate *this,
 166                        struct ldr_section_info *info);
 167
 168/* dynamic_loader_initialize */
 169static int connect(struct dynamic_loader_initialize *this);
 170static int read_mem(struct dynamic_loader_initialize *this, void *buf,
 171                    ldr_addr addr, struct ldr_section_info *info,
 172                    unsigned bytes);
 173static int write_mem(struct dynamic_loader_initialize *this, void *buf,
 174                     ldr_addr addr, struct ldr_section_info *info,
 175                     unsigned nbytes);
 176static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
 177                    struct ldr_section_info *info, unsigned bytes,
 178                    unsigned val);
 179static int execute(struct dynamic_loader_initialize *this, ldr_addr start);
 180static void release(struct dynamic_loader_initialize *this);
 181
 182/* symbol table hash functions */
 183static u32 name_hash(const void *key);
 184static bool name_match(const void *key, const void *sp);
 185static void sym_delete(void *value);
 186
 187/* Symbol Redefinition */
 188static int redefined_symbol;
 189static int gbl_search = 1;
 190
 191/*
 192 *  ======== dbll_close ========
 193 */
 194void dbll_close(struct dbll_library_obj *zl_lib)
 195{
 196        struct dbll_tar_obj *zl_target;
 197
 198        zl_target = zl_lib->target_obj;
 199        zl_lib->open_ref--;
 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;
 204
 205                if (zl_lib->prev)
 206                        (zl_lib->prev)->next = zl_lib->next;
 207
 208                if (zl_lib->next)
 209                        (zl_lib->next)->prev = zl_lib->prev;
 210
 211                /* Free DOF resources */
 212                dof_close(zl_lib);
 213                kfree(zl_lib->file_name);
 214
 215                /* remove symbols from symbol table */
 216                if (zl_lib->sym_tab)
 217                        gh_delete(zl_lib->sym_tab);
 218
 219                /* remove the library object itself */
 220                kfree(zl_lib);
 221                zl_lib = NULL;
 222        }
 223}
 224
 225/*
 226 *  ======== dbll_create ========
 227 */
 228int dbll_create(struct dbll_tar_obj **target_obj,
 229                       struct dbll_attrs *pattrs)
 230{
 231        struct dbll_tar_obj *pzl_target;
 232        int status = 0;
 233
 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) {
 238                        *target_obj = NULL;
 239                        status = -ENOMEM;
 240                } else {
 241                        pzl_target->attrs = *pattrs;
 242                        *target_obj = (struct dbll_tar_obj *)pzl_target;
 243                }
 244        }
 245
 246        return status;
 247}
 248
 249/*
 250 *  ======== dbll_delete ========
 251 */
 252void dbll_delete(struct dbll_tar_obj *target)
 253{
 254        struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
 255
 256        kfree(zl_target);
 257
 258}
 259
 260/*
 261 *  ======== dbll_exit ========
 262 *  Discontinue usage of DBL module.
 263 */
 264void dbll_exit(void)
 265{
 266        /* do nothing */
 267}
 268
 269/*
 270 *  ======== dbll_get_addr ========
 271 *  Get address of name in the specified library.
 272 */
 273bool dbll_get_addr(struct dbll_library_obj *zl_lib, char *name,
 274                   struct dbll_sym_val **sym_val)
 275{
 276        struct dbll_symbol *sym;
 277
 278        sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, name);
 279        if (IS_ERR(sym))
 280                return false;
 281
 282        *sym_val = &sym->value;
 283
 284        dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p\n",
 285                __func__, zl_lib, name, sym_val);
 286        return true;
 287}
 288
 289/*
 290 *  ======== dbll_get_attrs ========
 291 *  Retrieve the attributes of the target.
 292 */
 293void dbll_get_attrs(struct dbll_tar_obj *target, struct dbll_attrs *pattrs)
 294{
 295        struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
 296
 297        if ((pattrs != NULL) && (zl_target != NULL))
 298                *pattrs = zl_target->attrs;
 299
 300}
 301
 302/*
 303 *  ======== dbll_get_c_addr ========
 304 *  Get address of a "C" name in the specified library.
 305 */
 306bool dbll_get_c_addr(struct dbll_library_obj *zl_lib, char *name,
 307                     struct dbll_sym_val **sym_val)
 308{
 309        struct dbll_symbol *sym;
 310        char cname[MAXEXPR + 1];
 311
 312        cname[0] = '_';
 313
 314        strncpy(cname + 1, name, sizeof(cname) - 2);
 315        cname[MAXEXPR] = '\0';  /* insure '\0' string termination */
 316
 317        /* Check for C name, if not found */
 318        sym = (struct dbll_symbol *)gh_find(zl_lib->sym_tab, cname);
 319        if (IS_ERR(sym))
 320                return false;
 321
 322        *sym_val = &sym->value;
 323
 324        return true;
 325}
 326
 327/*
 328 *  ======== dbll_get_sect ========
 329 *  Get the base address and size (in bytes) of a COFF section.
 330 */
 331int dbll_get_sect(struct dbll_library_obj *lib, char *name, u32 *paddr,
 332                         u32 *psize)
 333{
 334        u32 byte_size;
 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;
 338        int status = 0;
 339
 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);
 344                        if (!status)
 345                                opened_doff = true;
 346
 347                } else {
 348                        (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
 349                                                              zl_lib->pos,
 350                                                              SEEK_SET);
 351                }
 352        } else {
 353                status = -EFAULT;
 354        }
 355        if (!status) {
 356                byte_size = 1;
 357                if (dload_get_section_info(zl_lib->desc, name, &sect)) {
 358                        *paddr = sect->load_addr;
 359                        *psize = sect->size * byte_size;
 360                        /* Make sure size is even for good swap */
 361                        if (*psize % 2)
 362                                (*psize)++;
 363
 364                        /* Align size */
 365                        *psize = DOFF_ALIGN(*psize);
 366                } else {
 367                        status = -ENXIO;
 368                }
 369        }
 370        if (opened_doff) {
 371                dof_close(zl_lib);
 372                opened_doff = false;
 373        }
 374
 375        dev_dbg(bridge, "%s: lib: %p name: %s paddr: %p psize: %p, status 0x%x\n",
 376                        __func__, lib, name, paddr, psize, status);
 377
 378        return status;
 379}
 380
 381/*
 382 *  ======== dbll_init ========
 383 */
 384bool dbll_init(void)
 385{
 386        /* do nothing */
 387
 388        return true;
 389}
 390
 391/*
 392 *  ======== dbll_load ========
 393 */
 394int dbll_load(struct dbll_library_obj *lib, dbll_flags flags,
 395                     struct dbll_attrs *attrs, u32 *entry)
 396{
 397        struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
 398        struct dbll_tar_obj *dbzl;
 399        bool got_symbols = true;
 400        s32 err;
 401        int status = 0;
 402        bool opened_doff = false;
 403
 404        /*
 405         *  Load if not already loaded.
 406         */
 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) {
 412                        got_symbols = false;
 413                        zl_lib->sym_tab = gh_create(sizeof(struct dbll_symbol),
 414                                                    name_hash,
 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;
 419                        }
 420
 421                }
 422                /*
 423                 *  Set up objects needed by the dynamic loader
 424                 */
 425                /* Stream */
 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;
 429                /* Symbol */
 430                zl_lib->symbol.dl_symbol.find_matching_symbol =
 431                    dbll_find_symbol;
 432                if (got_symbols) {
 433                        zl_lib->symbol.dl_symbol.add_to_symbol_table =
 434                            find_in_symbol_table;
 435                } else {
 436                        zl_lib->symbol.dl_symbol.add_to_symbol_table =
 437                            dbll_add_to_symbol_table;
 438                }
 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;
 445                /* Allocate */
 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;
 449                /* Init */
 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);
 460                        if (!status)
 461                                opened_doff = true;
 462
 463                }
 464                if (!status) {
 465                        zl_lib->pos = (*(zl_lib->target_obj->attrs.ftell))
 466                            (zl_lib->fp);
 467                        /* Reset file cursor */
 468                        (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
 469                                                              (long)0,
 470                                                              SEEK_SET);
 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,
 480                                                  DLOAD_INITBSS,
 481                                                  &zl_lib->dload_mod_obj);
 482
 483                        if (err != 0) {
 484                                status = -EILSEQ;
 485                        } else if (redefined_symbol) {
 486                                zl_lib->load_ref++;
 487                                dbll_unload(zl_lib, (struct dbll_attrs *)attrs);
 488                                redefined_symbol = false;
 489                                status = -EILSEQ;
 490                        } else {
 491                                *entry = zl_lib->entry;
 492                        }
 493                }
 494        }
 495        if (!status)
 496                zl_lib->load_ref++;
 497
 498        /* Clean up DOFF resources */
 499        if (opened_doff)
 500                dof_close(zl_lib);
 501
 502        dev_dbg(bridge, "%s: lib: %p flags: 0x%x entry: %p, status 0x%x\n",
 503                __func__, lib, flags, entry, status);
 504
 505        return status;
 506}
 507
 508/*
 509 *  ======== dbll_open ========
 510 */
 511int dbll_open(struct dbll_tar_obj *target, char *file, dbll_flags flags,
 512                     struct dbll_library_obj **lib_obj)
 513{
 514        struct dbll_tar_obj *zl_target = (struct dbll_tar_obj *)target;
 515        struct dbll_library_obj *zl_lib = NULL;
 516        s32 err;
 517        int status = 0;
 518
 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 */
 523                        zl_lib->open_ref++;
 524                        break;
 525                }
 526                zl_lib = zl_lib->next;
 527        }
 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) {
 532                        status = -ENOMEM;
 533                } else {
 534                        zl_lib->pos = 0;
 535                        /* Increment ref count to allow close on failure
 536                         * later on */
 537                        zl_lib->open_ref++;
 538                        zl_lib->target_obj = zl_target;
 539                        /* Keep a copy of the file name */
 540                        zl_lib->file_name = kzalloc(strlen(file) + 1,
 541                                                        GFP_KERNEL);
 542                        if (zl_lib->file_name == NULL) {
 543                                status = -ENOMEM;
 544                        } else {
 545                                strncpy(zl_lib->file_name, file,
 546                                        strlen(file) + 1);
 547                        }
 548                        zl_lib->sym_tab = NULL;
 549                }
 550        }
 551        /*
 552         *  Set up objects needed by the dynamic loader
 553         */
 554        if (status)
 555                goto func_cont;
 556
 557        /* Stream */
 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;
 561        /* Symbol */
 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;
 569        /* Allocate */
 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;
 573        /* Init */
 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);
 583
 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))
 588                goto func_cont;
 589
 590        zl_lib->sym_tab =
 591            gh_create(sizeof(struct dbll_symbol), name_hash, name_match,
 592                      sym_delete);
 593        if (IS_ERR(zl_lib->sym_tab)) {
 594                status = PTR_ERR(zl_lib->sym_tab);
 595                zl_lib->sym_tab = NULL;
 596        } else {
 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);
 604                if (err != 0) {
 605                        status = -EILSEQ;
 606                } else {
 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);
 612                        if (err != 0)
 613                                status = -EILSEQ;
 614
 615                        zl_lib->dload_mod_obj = NULL;
 616                }
 617        }
 618func_cont:
 619        if (!status) {
 620                if (zl_lib->open_ref == 1) {
 621                        /* First time opened - insert in list */
 622                        if (zl_target->head)
 623                                (zl_target->head)->prev = zl_lib;
 624
 625                        zl_lib->prev = NULL;
 626                        zl_lib->next = zl_target->head;
 627                        zl_target->head = zl_lib;
 628                }
 629                *lib_obj = (struct dbll_library_obj *)zl_lib;
 630        } else {
 631                *lib_obj = NULL;
 632                if (zl_lib != NULL)
 633                        dbll_close((struct dbll_library_obj *)zl_lib);
 634
 635        }
 636
 637        dev_dbg(bridge, "%s: target: %p file: %s lib_obj: %p, status 0x%x\n",
 638                __func__, target, file, lib_obj, status);
 639
 640        return status;
 641}
 642
 643/*
 644 *  ======== dbll_read_sect ========
 645 *  Get the content of a COFF section.
 646 */
 647int dbll_read_sect(struct dbll_library_obj *lib, char *name,
 648                          char *buf, u32 size)
 649{
 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;
 655        int status = 0;
 656
 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);
 661                        if (!status)
 662                                opened_doff = true;
 663
 664                } else {
 665                        (*(zl_lib->target_obj->attrs.fseek)) (zl_lib->fp,
 666                                                              zl_lib->pos,
 667                                                              SEEK_SET);
 668                }
 669        } else {
 670                status = -EFAULT;
 671        }
 672        if (status)
 673                goto func_cont;
 674
 675        byte_size = 1;
 676        if (!dload_get_section_info(zl_lib->desc, name, &sect)) {
 677                status = -ENXIO;
 678                goto func_cont;
 679        }
 680        /*
 681         * Ensure the supplied buffer size is sufficient to store
 682         * the section buf to be read.
 683         */
 684        ul_sect_size = sect->size * byte_size;
 685        /* Make sure size is even for good swap */
 686        if (ul_sect_size % 2)
 687                ul_sect_size++;
 688
 689        /* Align size */
 690        ul_sect_size = DOFF_ALIGN(ul_sect_size);
 691        if (ul_sect_size > size) {
 692                status = -EPERM;
 693        } else {
 694                if (!dload_get_section(zl_lib->desc, sect, buf))
 695                        status = -EBADF;
 696
 697        }
 698func_cont:
 699        if (opened_doff) {
 700                dof_close(zl_lib);
 701                opened_doff = false;
 702        }
 703
 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);
 706        return status;
 707}
 708
 709/*
 710 *  ======== dbll_unload ========
 711 */
 712void dbll_unload(struct dbll_library_obj *lib, struct dbll_attrs *attrs)
 713{
 714        struct dbll_library_obj *zl_lib = (struct dbll_library_obj *)lib;
 715        s32 err = 0;
 716
 717        dev_dbg(bridge, "%s: lib: %p\n", __func__, lib);
 718        zl_lib->load_ref--;
 719        /* Unload only if reference count is 0 */
 720        if (zl_lib->load_ref != 0)
 721                return;
 722
 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);
 729                if (err != 0)
 730                        dev_dbg(bridge, "%s: failed: 0x%x\n", __func__, err);
 731        }
 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;
 736        }
 737        /* delete DOFF desc since it holds *lots* of host OS
 738         * resources */
 739        dof_close(zl_lib);
 740}
 741
 742/*
 743 *  ======== dof_close ========
 744 */
 745static void dof_close(struct dbll_library_obj *zl_lib)
 746{
 747        if (zl_lib->desc) {
 748                dload_module_close(zl_lib->desc);
 749                zl_lib->desc = NULL;
 750        }
 751        /* close file */
 752        if (zl_lib->fp) {
 753                (zl_lib->target_obj->attrs.fclose) (zl_lib->fp);
 754                zl_lib->fp = NULL;
 755        }
 756}
 757
 758/*
 759 *  ======== dof_open ========
 760 */
 761static int dof_open(struct dbll_library_obj *zl_lib)
 762{
 763        void *open = *(zl_lib->target_obj->attrs.fopen);
 764        int status = 0;
 765
 766        /* First open the file for the dynamic loader, then open COF */
 767        zl_lib->fp =
 768            (void *)((dbll_f_open_fxn) (open)) (zl_lib->file_name, "rb");
 769
 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,
 773                                                      SEEK_SET);
 774                zl_lib->desc =
 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);
 779                        zl_lib->fp = NULL;
 780                        status = -EBADF;
 781                }
 782        } else {
 783                status = -EBADF;
 784        }
 785
 786        return status;
 787}
 788
 789/*
 790 *  ======== name_hash ========
 791 */
 792static u32 name_hash(const void *key)
 793{
 794        u32 hash;
 795        const char *name = key;
 796
 797        hash = 0;
 798
 799        while (*name) {
 800                hash <<= 1;
 801                hash ^= *name++;
 802        }
 803
 804        return hash;
 805}
 806
 807/*
 808 *  ======== name_match ========
 809 */
 810static bool name_match(const void *key, const void *sp)
 811{
 812        if ((key != NULL) && (sp != NULL)) {
 813                if (strcmp(key, ((struct dbll_symbol *)sp)->name) == 0)
 814                        return true;
 815        }
 816        return false;
 817}
 818
 819/*
 820 *  ======== no_op ========
 821 */
 822static int no_op(struct dynamic_loader_initialize *thisptr, void *bufr,
 823                 ldr_addr locn, struct ldr_section_info *info, unsigned bytsize)
 824{
 825        return 1;
 826}
 827
 828/*
 829 *  ======== sym_delete ========
 830 */
 831static void sym_delete(void *value)
 832{
 833        struct dbll_symbol *sp = (struct dbll_symbol *)value;
 834
 835        kfree(sp->name);
 836}
 837
 838/*
 839 *  Dynamic Loader Functions
 840 */
 841
 842/* dynamic_loader_stream */
 843/*
 844 *  ======== dbll_read_buffer ========
 845 */
 846static int dbll_read_buffer(struct dynamic_loader_stream *this, void *buffer,
 847                            unsigned bufsize)
 848{
 849        struct dbll_stream *pstream = (struct dbll_stream *)this;
 850        struct dbll_library_obj *lib;
 851        int bytes_read = 0;
 852
 853        lib = pstream->lib;
 854        if (lib != NULL) {
 855                bytes_read =
 856                    (*(lib->target_obj->attrs.fread)) (buffer, 1, bufsize,
 857                                                       lib->fp);
 858        }
 859        return bytes_read;
 860}
 861
 862/*
 863 *  ======== dbll_set_file_posn ========
 864 */
 865static int dbll_set_file_posn(struct dynamic_loader_stream *this,
 866                              unsigned int pos)
 867{
 868        struct dbll_stream *pstream = (struct dbll_stream *)this;
 869        struct dbll_library_obj *lib;
 870        int status = 0;         /* Success */
 871
 872        lib = pstream->lib;
 873        if (lib != NULL) {
 874                status = (*(lib->target_obj->attrs.fseek)) (lib->fp, (long)pos,
 875                                                            SEEK_SET);
 876        }
 877
 878        return status;
 879}
 880
 881/* dynamic_loader_sym */
 882
 883/*
 884 *  ======== dbll_find_symbol ========
 885 */
 886static struct dynload_symbol *dbll_find_symbol(struct dynamic_loader_sym *this,
 887                                               const char *name)
 888{
 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 */
 894
 895        lib = ldr_sym->lib;
 896        if (lib != NULL) {
 897                if (lib->target_obj->attrs.sym_lookup) {
 898                        /* Check current lib + base lib + dep lib +
 899                         * persistent 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,
 904                             &dbll_sym);
 905                } else {
 906                        /* Just check current lib for symbol */
 907                        status = dbll_get_addr((struct dbll_library_obj *)lib,
 908                                               (char *)name, &dbll_sym);
 909                        if (!status) {
 910                                status = dbll_get_c_addr(
 911                                                (struct dbll_library_obj *)
 912                                                lib, (char *)name,
 913                                                &dbll_sym);
 914                        }
 915                }
 916        }
 917
 918        if (!status && gbl_search)
 919                dev_dbg(bridge, "%s: Symbol not found: %s\n", __func__, name);
 920
 921        ret_sym = (struct dynload_symbol *)dbll_sym;
 922        return ret_sym;
 923}
 924
 925/*
 926 *  ======== find_in_symbol_table ========
 927 */
 928static struct dynload_symbol *find_in_symbol_table(struct dynamic_loader_sym
 929                                                   *this, const char *name,
 930                                                   unsigned moduleid)
 931{
 932        struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
 933        struct dbll_library_obj *lib;
 934        struct dbll_symbol *sym;
 935
 936        lib = ldr_sym->lib;
 937        sym = (struct dbll_symbol *)gh_find(lib->sym_tab, (char *)name);
 938
 939        if (IS_ERR(sym))
 940                return NULL;
 941
 942        return (struct dynload_symbol *)&sym->value;
 943}
 944
 945/*
 946 *  ======== dbll_add_to_symbol_table ========
 947 */
 948static struct dynload_symbol *dbll_add_to_symbol_table(struct dynamic_loader_sym
 949                                                       *this, const char *name,
 950                                                       unsigned module_id)
 951{
 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;
 958
 959        lib = ldr_sym->lib;
 960
 961        /* Check to see if symbol is already defined in symbol table */
 962        if (!(lib->target_obj->attrs.base_image)) {
 963                gbl_search = false;
 964                dbll_sym = dbll_find_symbol(this, name);
 965                gbl_search = true;
 966                if (dbll_sym) {
 967                        redefined_symbol = true;
 968                        dev_dbg(bridge, "%s already defined in symbol table\n",
 969                                name);
 970                        return NULL;
 971                }
 972        }
 973        /* Allocate string to copy symbol name */
 974        symbol.name = kzalloc(strlen((char *const)name) + 1, GFP_KERNEL);
 975        if (symbol.name == NULL)
 976                return NULL;
 977
 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);
 982
 983                /* Add symbol to symbol table */
 984                sym_ptr =
 985                    (struct dbll_symbol *)gh_insert(lib->sym_tab, (void *)name,
 986                                                    (void *)&symbol);
 987                if (IS_ERR(sym_ptr)) {
 988                        kfree(symbol.name);
 989                        sym_ptr = NULL;
 990                }
 991
 992        }
 993        if (sym_ptr != NULL)
 994                ret = (struct dynload_symbol *)&sym_ptr->value;
 995        else
 996                ret = NULL;
 997
 998        return ret;
 999}
1000
1001/*
1002 *  ======== dbll_purge_symbol_table ========
1003 */
1004static void dbll_purge_symbol_table(struct dynamic_loader_sym *this,
1005                                    unsigned module_id)
1006{
1007        struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1008        struct dbll_library_obj *lib;
1009
1010        lib = ldr_sym->lib;
1011        /* May not need to do anything */
1012}
1013
1014/*
1015 *  ======== allocate ========
1016 */
1017static void *allocate(struct dynamic_loader_sym *this, unsigned memsize)
1018{
1019        struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1020        struct dbll_library_obj *lib;
1021        void *buf;
1022
1023        lib = ldr_sym->lib;
1024
1025        buf = kzalloc(memsize, GFP_KERNEL);
1026
1027        return buf;
1028}
1029
1030/*
1031 *  ======== deallocate ========
1032 */
1033static void deallocate(struct dynamic_loader_sym *this, void *mem_ptr)
1034{
1035        struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1036        struct dbll_library_obj *lib;
1037
1038        lib = ldr_sym->lib;
1039
1040        kfree(mem_ptr);
1041}
1042
1043/*
1044 *  ======== dbll_err_report ========
1045 */
1046static void dbll_err_report(struct dynamic_loader_sym *this, const char *errstr,
1047                            va_list args)
1048{
1049        struct ldr_symbol *ldr_sym = (struct ldr_symbol *)this;
1050        struct dbll_library_obj *lib;
1051        char temp_buf[MAXEXPR];
1052
1053        lib = ldr_sym->lib;
1054        vsnprintf((char *)temp_buf, MAXEXPR, (char *)errstr, args);
1055        dev_dbg(bridge, "%s\n", temp_buf);
1056}
1057
1058/* dynamic_loader_allocate */
1059
1060/*
1061 *  ======== dbll_rmm_alloc ========
1062 */
1063static int dbll_rmm_alloc(struct dynamic_loader_allocate *this,
1064                          struct ldr_section_info *info, unsigned align)
1065{
1066        struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1067        struct dbll_library_obj *lib;
1068        int status = 0;
1069        u32 mem_sect_type;
1070        struct rmm_addr rmm_addr_obj;
1071        s32 ret = true;
1072        unsigned stype = DLOAD_SECTION_TYPE(info->type);
1073        char *token = NULL;
1074        char *sz_sec_last_token = NULL;
1075        char *sz_last_token = NULL;
1076        char *sz_sect_name = NULL;
1077        char *psz_cur;
1078        s32 token_len = 0;
1079        s32 seg_id = -1;
1080        s32 req = -1;
1081        s32 count = 0;
1082        u32 alloc_size = 0;
1083        u32 run_addr_flag = 0;
1084
1085        lib = dbll_alloc_obj->lib;
1086
1087        mem_sect_type =
1088            (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1089                                                 DLOAD_BSS) ? DBLL_BSS :
1090            DBLL_DATA;
1091
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;
1095
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);
1099
1100        if (sz_sect_name == NULL || sz_sec_last_token == NULL ||
1101            sz_last_token == NULL) {
1102                status = -ENOMEM;
1103                goto func_cont;
1104        }
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 */
1113        }
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) */
1118        if (count >= 3) {
1119                status = kstrtos32(sz_last_token, 10, &req);
1120                if (status)
1121                        goto func_cont;
1122        }
1123
1124        if ((req == 0) || (req == 1)) {
1125                if (strcmp(sz_sec_last_token, "DYN_DARAM") == 0) {
1126                        seg_id = 0;
1127                } else {
1128                        if (strcmp(sz_sec_last_token, "DYN_SARAM") == 0) {
1129                                seg_id = 1;
1130                        } else {
1131                                if (strcmp(sz_sec_last_token,
1132                                           "DYN_EXTERNAL") == 0)
1133                                        seg_id = 2;
1134                        }
1135                }
1136        }
1137func_cont:
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;
1144
1145        if (mem_sect_type == DBLL_CODE)
1146                alloc_size = info->size + GEM_L1P_PREFETCH_SIZE;
1147        else
1148                alloc_size = info->size;
1149
1150        if (info->load_addr != info->run_addr)
1151                run_addr_flag = 1;
1152        /* TODO - ideally, we can pass the alignment requirement also
1153         * from here */
1154        if (lib != NULL) {
1155                status =
1156                    (lib->target_obj->attrs.alloc) (lib->target_obj->attrs.
1157                                                    rmm_handle, mem_sect_type,
1158                                                    alloc_size, align,
1159                                                    (u32 *) &rmm_addr_obj,
1160                                                    seg_id, req, false);
1161        }
1162        if (status) {
1163                ret = false;
1164        } else {
1165                /* RMM gives word address. Need to convert to byte address */
1166                info->load_addr = rmm_addr_obj.addr * DSPWORDSIZE;
1167                if (!run_addr_flag)
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,
1173                        info->load_addr);
1174        }
1175        return ret;
1176}
1177
1178/*
1179 *  ======== rmm_dealloc ========
1180 */
1181static void rmm_dealloc(struct dynamic_loader_allocate *this,
1182                        struct ldr_section_info *info)
1183{
1184        struct dbll_alloc *dbll_alloc_obj = (struct dbll_alloc *)this;
1185        struct dbll_library_obj *lib;
1186        u32 segid;
1187        int status = 0;
1188        unsigned stype = DLOAD_SECTION_TYPE(info->type);
1189        u32 mem_sect_type;
1190        u32 free_size = 0;
1191
1192        mem_sect_type =
1193            (stype == DLOAD_TEXT) ? DBLL_CODE : (stype ==
1194                                                 DLOAD_BSS) ? DBLL_BSS :
1195            DBLL_DATA;
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;
1201        else
1202                free_size = info->size;
1203        if (lib != NULL) {
1204                status =
1205                    (lib->target_obj->attrs.free) (lib->target_obj->attrs.
1206                                                   sym_handle, segid,
1207                                                   info->load_addr /
1208                                                   DSPWORDSIZE, free_size,
1209                                                   false);
1210        }
1211}
1212
1213/* dynamic_loader_initialize */
1214/*
1215 *  ======== connect ========
1216 */
1217static int connect(struct dynamic_loader_initialize *this)
1218{
1219        return true;
1220}
1221
1222/*
1223 *  ======== read_mem ========
1224 *  This function does not need to be implemented.
1225 */
1226static int read_mem(struct dynamic_loader_initialize *this, void *buf,
1227                    ldr_addr addr, struct ldr_section_info *info,
1228                    unsigned nbytes)
1229{
1230        struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1231        struct dbll_library_obj *lib;
1232        int bytes_read = 0;
1233
1234        lib = init_obj->lib;
1235        /* Need bridge_brd_read function */
1236        return bytes_read;
1237}
1238
1239/*
1240 *  ======== write_mem ========
1241 */
1242static int write_mem(struct dynamic_loader_initialize *this, void *buf,
1243                     ldr_addr addr, struct ldr_section_info *info,
1244                     unsigned bytes)
1245{
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;
1250        u32 mem_sect_type;
1251        bool ret = true;
1252
1253        lib = init_obj->lib;
1254        if (!lib)
1255                return false;
1256
1257        target_obj = lib->target_obj;
1258
1259        mem_sect_type =
1260            (DLOAD_SECTION_TYPE(info->type) ==
1261             DLOAD_TEXT) ? DBLL_CODE : DBLL_DATA;
1262        if (target_obj && target_obj->attrs.write) {
1263                ret =
1264                    (*target_obj->attrs.write) (target_obj->attrs.input_params,
1265                                                addr, buf, bytes,
1266                                                mem_sect_type);
1267
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
1275                         * another module */
1276                        (*target_obj->attrs.log_write) (target_obj->attrs.
1277                                                        log_write_handle,
1278                                                        &sect_info, addr,
1279                                                        bytes);
1280                }
1281        }
1282        return ret;
1283}
1284
1285/*
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.
1290 */
1291static int fill_mem(struct dynamic_loader_initialize *this, ldr_addr addr,
1292                    struct ldr_section_info *info, unsigned bytes, unsigned val)
1293{
1294        bool ret = true;
1295        char *pbuf;
1296        struct dbll_library_obj *lib;
1297        struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1298
1299        lib = init_obj->lib;
1300        pbuf = NULL;
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
1304         */
1305        if ((lib->target_obj->attrs.write) != (dbll_write_fxn) no_op)
1306                write_mem(this, &pbuf, addr, info, 0);
1307        if (pbuf)
1308                memset(pbuf, val, bytes);
1309
1310        return ret;
1311}
1312
1313/*
1314 *  ======== execute ========
1315 */
1316static int execute(struct dynamic_loader_initialize *this, ldr_addr start)
1317{
1318        struct dbll_init_obj *init_obj = (struct dbll_init_obj *)this;
1319        struct dbll_library_obj *lib;
1320        bool ret = true;
1321
1322        lib = init_obj->lib;
1323        /* Save entry point */
1324        if (lib != NULL)
1325                lib->entry = (u32) start;
1326
1327        return ret;
1328}
1329
1330/*
1331 *  ======== release ========
1332 */
1333static void release(struct dynamic_loader_initialize *this)
1334{
1335}
1336
1337#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1338/**
1339 *  find_symbol_context - Basic symbol context structure
1340 * @address:            Symbol Address
1341 * @offset_range:               Offset range where the search for the DSP symbol
1342 *                      started.
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
1346 *
1347 */
1348struct find_symbol_context {
1349        /* input */
1350        u32 address;
1351        u32 offset_range;
1352        /* state */
1353        u32 cur_best_offset;
1354        /* output */
1355        u32 sym_addr;
1356        char name[120];
1357};
1358
1359/**
1360 * find_symbol_callback() - Validates symbol address and copies the symbol name
1361 *                      to the user data.
1362 * @elem:               dsp library context
1363 * @user_data:          Find symbol context
1364 *
1365 */
1366void find_symbol_callback(void *elem, void *user_data)
1367{
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;
1372
1373        /*
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
1377         */
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));
1383        }
1384
1385        return;
1386}
1387
1388/**
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
1395 *
1396 *      This function retrieves the dsp symbol from the dsp binary.
1397 */
1398bool dbll_find_dsp_symbol(struct dbll_library_obj *zl_lib, u32 address,
1399                                u32 offset_range, u32 *sym_addr_output,
1400                                char *name_output)
1401{
1402        bool status = false;
1403        struct find_symbol_context context;
1404
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';
1410
1411        gh_iterate(zl_lib->sym_tab, find_symbol_callback, &context);
1412
1413        if (context.name[0]) {
1414                status = true;
1415                strcpy(name_output, context.name);
1416                *sym_addr_output = context.sym_addr;
1417        }
1418
1419        return status;
1420}
1421#endif
1422