linux/drivers/staging/tidspbridge/dynload/cload.c
<<
>>
Prefs
   1/*
   2 * cload.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
  17#include <linux/slab.h>
  18
  19#include "header.h"
  20
  21#include "module_list.h"
  22#define LINKER_MODULES_HEADER ("_" MODULES_HEADER)
  23
  24/*
  25 * forward references
  26 */
  27static void dload_symbols(struct dload_state *dlthis);
  28static void dload_data(struct dload_state *dlthis);
  29static void allocate_sections(struct dload_state *dlthis);
  30static void string_table_free(struct dload_state *dlthis);
  31static void symbol_table_free(struct dload_state *dlthis);
  32static void section_table_free(struct dload_state *dlthis);
  33static void init_module_handle(struct dload_state *dlthis);
  34#if BITS_PER_AU > BITS_PER_BYTE
  35static char *unpack_name(struct dload_state *dlthis, u32 soffset);
  36#endif
  37
  38static const char cinitname[] = { ".cinit" };
  39static const char loader_dllview_root[] = { "?DLModules?" };
  40
  41/*
  42 * Error strings
  43 */
  44static const char readstrm[] = { "Error reading %s from input stream" };
  45static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
  46static const char tgtalloc[] = {
  47        "Target memory allocate failed, section %s size " FMT_UI32 };
  48static const char initfail[] = { "%s to target address " FMT_UI32 " failed" };
  49static const char dlvwrite[] = { "Write to DLLview list failed" };
  50static const char iconnect[] = { "Connect call to init interface failed" };
  51static const char err_checksum[] = { "Checksum failed on %s" };
  52
  53/*************************************************************************
  54 * Procedure dload_error
  55 *
  56 * Parameters:
  57 *      errtxt  description of the error, printf style
  58 *      ...             additional information
  59 *
  60 * Effect:
  61 *      Reports or records the error as appropriate.
  62 *********************************************************************** */
  63void dload_error(struct dload_state *dlthis, const char *errtxt, ...)
  64{
  65        va_list args;
  66
  67        va_start(args, errtxt);
  68        dlthis->mysym->error_report(dlthis->mysym, errtxt, args);
  69        va_end(args);
  70        dlthis->dload_errcount += 1;
  71
  72}                               /* dload_error */
  73
  74#define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb)
  75
  76/*************************************************************************
  77 * Procedure dload_syms_error
  78 *
  79 * Parameters:
  80 *      errtxt  description of the error, printf style
  81 *      ...             additional information
  82 *
  83 * Effect:
  84 *      Reports or records the error as appropriate.
  85 *********************************************************************** */
  86void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...)
  87{
  88        va_list args;
  89
  90        va_start(args, errtxt);
  91        syms->error_report(syms, errtxt, args);
  92        va_end(args);
  93}
  94
  95/*************************************************************************
  96 * Procedure dynamic_load_module
  97 *
  98 * Parameters:
  99 *      module  The input stream that supplies the module image
 100 *      syms    Host-side symbol table and malloc/free functions
 101 *      alloc   Target-side memory allocation
 102 *      init    Target-side memory initialization
 103 *      options Option flags DLOAD_*
 104 *      mhandle A module handle for use with Dynamic_Unload
 105 *
 106 * Effect:
 107 *      The module image is read using *module.  Target storage for the new
 108 *      image is
 109 * obtained from *alloc.  Symbols defined and referenced by the module are
 110 * managed using *syms.  The image is then relocated and references
 111 *      resolved as necessary, and the resulting executable bits are placed
 112 *      into target memory using *init.
 113 *
 114 * Returns:
 115 *      On a successful load, a module handle is placed in *mhandle,
 116 *      and zero is returned.  On error, the number of errors detected is
 117 *      returned.  Individual errors are reported during the load process
 118 *      using syms->error_report().
 119 ********************************************************************** */
 120int dynamic_load_module(struct dynamic_loader_stream *module,
 121                        struct dynamic_loader_sym *syms,
 122                        struct dynamic_loader_allocate *alloc,
 123                        struct dynamic_loader_initialize *init,
 124                        unsigned options, void **mhandle)
 125{
 126        register unsigned *dp, sz;
 127        struct dload_state dl_state;    /* internal state for this call */
 128
 129        /* blast our internal state */
 130        dp = (unsigned *)&dl_state;
 131        for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
 132                *dp++ = 0;
 133
 134        /* Enable _only_ BSS initialization if enabled by user */
 135        if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
 136                dl_state.myoptions = DLOAD_INITBSS;
 137
 138        /* Check that mandatory arguments are present */
 139        if (!module || !syms) {
 140                dload_error(&dl_state, "Required parameter is NULL");
 141        } else {
 142                dl_state.strm = module;
 143                dl_state.mysym = syms;
 144                dload_headers(&dl_state);
 145                if (!dl_state.dload_errcount)
 146                        dload_strings(&dl_state, false);
 147                if (!dl_state.dload_errcount)
 148                        dload_sections(&dl_state);
 149
 150                if (init && !dl_state.dload_errcount) {
 151                        if (init->connect(init)) {
 152                                dl_state.myio = init;
 153                                dl_state.myalloc = alloc;
 154                                /* do now, before reducing symbols */
 155                                allocate_sections(&dl_state);
 156                        } else
 157                                dload_error(&dl_state, iconnect);
 158                }
 159
 160                if (!dl_state.dload_errcount) {
 161                        /* fix up entry point address */
 162                        unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
 163                        if (sref < dl_state.allocated_secn_count)
 164                                dl_state.dfile_hdr.df_entrypt +=
 165                                    dl_state.ldr_sections[sref].run_addr;
 166
 167                        dload_symbols(&dl_state);
 168                }
 169
 170                if (init && !dl_state.dload_errcount)
 171                        dload_data(&dl_state);
 172
 173                init_module_handle(&dl_state);
 174
 175                /* dl_state.myio is init or 0 at this point. */
 176                if (dl_state.myio) {
 177                        if ((!dl_state.dload_errcount) &&
 178                            (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
 179                            (!init->execute(init,
 180                                            dl_state.dfile_hdr.df_entrypt)))
 181                                dload_error(&dl_state, "Init->Execute Failed");
 182                        init->release(init);
 183                }
 184
 185                symbol_table_free(&dl_state);
 186                section_table_free(&dl_state);
 187                string_table_free(&dl_state);
 188                dload_tramp_cleanup(&dl_state);
 189
 190                if (dl_state.dload_errcount) {
 191                        dynamic_unload_module(dl_state.myhandle, syms, alloc,
 192                                              init);
 193                        dl_state.myhandle = NULL;
 194                }
 195        }
 196
 197        if (mhandle)
 198                *mhandle = dl_state.myhandle;   /* give back the handle */
 199
 200        return dl_state.dload_errcount;
 201}                               /* DLOAD_File */
 202
 203/*************************************************************************
 204 * Procedure dynamic_open_module
 205 *
 206 * Parameters:
 207 *      module  The input stream that supplies the module image
 208 *      syms    Host-side symbol table and malloc/free functions
 209 *      alloc   Target-side memory allocation
 210 *      init    Target-side memory initialization
 211 *      options Option flags DLOAD_*
 212 *      mhandle A module handle for use with Dynamic_Unload
 213 *
 214 * Effect:
 215 *      The module image is read using *module.  Target storage for the new
 216 *      image is
 217 *      obtained from *alloc.  Symbols defined and referenced by the module are
 218 *      managed using *syms.  The image is then relocated and references
 219 *      resolved as necessary, and the resulting executable bits are placed
 220 *      into target memory using *init.
 221 *
 222 * Returns:
 223 *      On a successful load, a module handle is placed in *mhandle,
 224 *      and zero is returned.  On error, the number of errors detected is
 225 *      returned.  Individual errors are reported during the load process
 226 *      using syms->error_report().
 227 ********************************************************************** */
 228int
 229dynamic_open_module(struct dynamic_loader_stream *module,
 230                    struct dynamic_loader_sym *syms,
 231                    struct dynamic_loader_allocate *alloc,
 232                    struct dynamic_loader_initialize *init,
 233                    unsigned options, void **mhandle)
 234{
 235        register unsigned *dp, sz;
 236        struct dload_state dl_state;    /* internal state for this call */
 237
 238        /* blast our internal state */
 239        dp = (unsigned *)&dl_state;
 240        for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
 241                *dp++ = 0;
 242
 243        /* Enable _only_ BSS initialization if enabled by user */
 244        if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
 245                dl_state.myoptions = DLOAD_INITBSS;
 246
 247        /* Check that mandatory arguments are present */
 248        if (!module || !syms) {
 249                dload_error(&dl_state, "Required parameter is NULL");
 250        } else {
 251                dl_state.strm = module;
 252                dl_state.mysym = syms;
 253                dload_headers(&dl_state);
 254                if (!dl_state.dload_errcount)
 255                        dload_strings(&dl_state, false);
 256                if (!dl_state.dload_errcount)
 257                        dload_sections(&dl_state);
 258
 259                if (init && !dl_state.dload_errcount) {
 260                        if (init->connect(init)) {
 261                                dl_state.myio = init;
 262                                dl_state.myalloc = alloc;
 263                                /* do now, before reducing symbols */
 264                                allocate_sections(&dl_state);
 265                        } else
 266                                dload_error(&dl_state, iconnect);
 267                }
 268
 269                if (!dl_state.dload_errcount) {
 270                        /* fix up entry point address */
 271                        unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
 272                        if (sref < dl_state.allocated_secn_count)
 273                                dl_state.dfile_hdr.df_entrypt +=
 274                                    dl_state.ldr_sections[sref].run_addr;
 275
 276                        dload_symbols(&dl_state);
 277                }
 278
 279                init_module_handle(&dl_state);
 280
 281                /* dl_state.myio is either 0 or init at this point. */
 282                if (dl_state.myio) {
 283                        if ((!dl_state.dload_errcount) &&
 284                            (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
 285                            (!init->execute(init,
 286                                            dl_state.dfile_hdr.df_entrypt)))
 287                                dload_error(&dl_state, "Init->Execute Failed");
 288                        init->release(init);
 289                }
 290
 291                symbol_table_free(&dl_state);
 292                section_table_free(&dl_state);
 293                string_table_free(&dl_state);
 294
 295                if (dl_state.dload_errcount) {
 296                        dynamic_unload_module(dl_state.myhandle, syms, alloc,
 297                                              init);
 298                        dl_state.myhandle = NULL;
 299                }
 300        }
 301
 302        if (mhandle)
 303                *mhandle = dl_state.myhandle;   /* give back the handle */
 304
 305        return dl_state.dload_errcount;
 306}                               /* DLOAD_File */
 307
 308/*************************************************************************
 309 * Procedure dload_headers
 310 *
 311 * Parameters:
 312 *      none
 313 *
 314 * Effect:
 315 *      Loads the DOFF header and verify record.  Deals with any byte-order
 316 * issues and checks them for validity.
 317 *********************************************************************** */
 318#define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \
 319                             sizeof(struct doff_verify_rec_t))
 320
 321void dload_headers(struct dload_state *dlthis)
 322{
 323        u32 map;
 324
 325        /* Read the header and the verify record as one.  If we don't get it
 326           all, we're done */
 327        if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr,
 328                                      COMBINED_HEADER_SIZE) !=
 329            COMBINED_HEADER_SIZE) {
 330                DL_ERROR(readstrm, "File Headers");
 331                return;
 332        }
 333        /*
 334         * Verify that we have the byte order of the file correct.
 335         * If not, must fix it before we can continue
 336         */
 337        map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle);
 338        if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) {
 339                /* input is either byte-shuffled or bad */
 340                if ((map & 0xFCFCFCFC) == 0) {  /* no obviously bogus bits */
 341                        dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE,
 342                                      map);
 343                }
 344                if (dlthis->dfile_hdr.df_byte_reshuffle !=
 345                    BYTE_RESHUFFLE_VALUE) {
 346                        /* didn't fix the problem, the byte swap map is bad */
 347                        dload_error(dlthis,
 348                                    "Bad byte swap map " FMT_UI32 " in header",
 349                                    dlthis->dfile_hdr.df_byte_reshuffle);
 350                        return;
 351                }
 352                dlthis->reorder_map = map;      /* keep map for future use */
 353        }
 354
 355        /*
 356         * Verify checksum of header and verify record
 357         */
 358        if (~dload_checksum(&dlthis->dfile_hdr,
 359                            sizeof(struct doff_filehdr_t)) ||
 360            ~dload_checksum(&dlthis->verify,
 361                            sizeof(struct doff_verify_rec_t))) {
 362                DL_ERROR(err_checksum, "header or verify record");
 363                return;
 364        }
 365#if HOST_ENDIANNESS
 366        dlthis->dfile_hdr.df_byte_reshuffle = map;      /* put back for later */
 367#endif
 368
 369        /* Check for valid target ID */
 370        if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) &&
 371            -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) {
 372                dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x",
 373                            dlthis->dfile_hdr.df_target_id, TARGET_ID);
 374                return;
 375        }
 376        /* Check for valid file format */
 377        if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) {
 378                dload_error(dlthis, "Bad DOFF version 0x%x",
 379                            dlthis->dfile_hdr.df_doff_version);
 380                return;
 381        }
 382
 383        /*
 384         * Apply reasonableness checks to count fields
 385         */
 386        if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) {
 387                dload_error(dlthis, "Excessive string table size " FMT_UI32,
 388                            dlthis->dfile_hdr.df_strtab_size);
 389                return;
 390        }
 391        if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) {
 392                dload_error(dlthis, "Excessive section count 0x%x",
 393                            dlthis->dfile_hdr.df_no_scns);
 394                return;
 395        }
 396#ifndef TARGET_ENDIANNESS
 397        /*
 398         * Check that endianness does not disagree with explicit specification
 399         */
 400        if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) &
 401            dlthis->myoptions & ENDIANNESS_MASK) {
 402                dload_error(dlthis,
 403                            "Input endianness disagrees with specified option");
 404                return;
 405        }
 406        dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG;
 407#endif
 408
 409}                               /* dload_headers */
 410
 411/*      COFF Section Processing
 412 *
 413 *      COFF sections are read in and retained intact.  Each record is embedded
 414 *      in a new structure that records the updated load and
 415 *      run addresses of the section */
 416
 417static const char secn_errid[] = { "section" };
 418
 419/*************************************************************************
 420 * Procedure dload_sections
 421 *
 422 * Parameters:
 423 *      none
 424 *
 425 * Effect:
 426 *      Loads the section records into an internal table.
 427 *********************************************************************** */
 428void dload_sections(struct dload_state *dlthis)
 429{
 430        s16 siz;
 431        struct doff_scnhdr_t *shp;
 432        unsigned nsecs = dlthis->dfile_hdr.df_no_scns;
 433
 434        /* allocate space for the DOFF section records */
 435        siz = nsecs * sizeof(struct doff_scnhdr_t);
 436        shp =
 437            (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym,
 438                                                                  siz);
 439        if (!shp) {             /* not enough storage */
 440                DL_ERROR(err_alloc, siz);
 441                return;
 442        }
 443        dlthis->sect_hdrs = shp;
 444
 445        /* read in the section records */
 446        if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) {
 447                DL_ERROR(readstrm, secn_errid);
 448                return;
 449        }
 450
 451        /* if we need to fix up byte order, do it now */
 452        if (dlthis->reorder_map)
 453                dload_reorder(shp, siz, dlthis->reorder_map);
 454
 455        /* check for validity */
 456        if (~dload_checksum(dlthis->sect_hdrs, siz) !=
 457            dlthis->verify.dv_scn_rec_checksum) {
 458                DL_ERROR(err_checksum, secn_errid);
 459                return;
 460        }
 461
 462}                               /* dload_sections */
 463
 464/*****************************************************************************
 465 * Procedure allocate_sections
 466 *
 467 * Parameters:
 468 *      alloc   target memory allocator class
 469 *
 470 * Effect:
 471 *      Assigns new (target) addresses for sections
 472 **************************************************************************** */
 473static void allocate_sections(struct dload_state *dlthis)
 474{
 475        u16 curr_sect, nsecs, siz;
 476        struct doff_scnhdr_t *shp;
 477        struct ldr_section_info *asecs;
 478        struct my_handle *hndl;
 479        nsecs = dlthis->dfile_hdr.df_no_scns;
 480        if (!nsecs)
 481                return;
 482        if ((dlthis->myalloc == NULL) &&
 483            (dlthis->dfile_hdr.df_target_scns > 0)) {
 484                DL_ERROR("Arg 3 (alloc) required but NULL", 0);
 485                return;
 486        }
 487        /*
 488         * allocate space for the module handle, which we will keep for unload
 489         * purposes include an additional section store for an auto-generated
 490         * trampoline section in case we need it.
 491         */
 492        siz = (dlthis->dfile_hdr.df_target_scns + 1) *
 493            sizeof(struct ldr_section_info) + MY_HANDLE_SIZE;
 494
 495        hndl =
 496            (struct my_handle *)dlthis->mysym->dload_allocate(dlthis->mysym,
 497                                                              siz);
 498        if (!hndl) {            /* not enough storage */
 499                DL_ERROR(err_alloc, siz);
 500                return;
 501        }
 502        /* initialize the handle header */
 503        hndl->dm.next = hndl->dm.prev = hndl;   /* circular list */
 504        hndl->dm.root = NULL;
 505        hndl->dm.dbthis = 0;
 506        dlthis->myhandle = hndl;        /* save away for return */
 507        /* pointer to the section list of allocated sections */
 508        dlthis->ldr_sections = asecs = hndl->secns;
 509        /* * Insert names into all sections, make copies of
 510           the sections we allocate */
 511        shp = dlthis->sect_hdrs;
 512        for (curr_sect = 0; curr_sect < nsecs; curr_sect++) {
 513                u32 soffset = shp->ds_offset;
 514#if BITS_PER_AU <= BITS_PER_BYTE
 515                /* attempt to insert the name of this section */
 516                if (soffset < dlthis->dfile_hdr.df_strtab_size)
 517                        ((struct ldr_section_info *)shp)->name =
 518                                dlthis->str_head + soffset;
 519                else {
 520                        dload_error(dlthis, "Bad name offset in section %d",
 521                                    curr_sect);
 522                        ((struct ldr_section_info *)shp)->name = NULL;
 523                }
 524#endif
 525                /* allocate target storage for sections that require it */
 526                if (ds_needs_allocation(shp)) {
 527                        *asecs = *(struct ldr_section_info *)shp;
 528                        asecs->context = 0;     /* zero the context field */
 529#if BITS_PER_AU > BITS_PER_BYTE
 530                        asecs->name = unpack_name(dlthis, soffset);
 531                        dlthis->debug_string_size = soffset + dlthis->temp_len;
 532#else
 533                        dlthis->debug_string_size = soffset;
 534#endif
 535                        if (dlthis->myalloc != NULL) {
 536                                if (!dlthis->myalloc->
 537                                    dload_allocate(dlthis->myalloc, asecs,
 538                                                   ds_alignment(asecs->type))) {
 539                                        dload_error(dlthis, tgtalloc,
 540                                                    asecs->name, asecs->size);
 541                                        return;
 542                                }
 543                        }
 544                        /* keep address deltas in original section table */
 545                        shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr;
 546                        shp->ds_paddr = asecs->run_addr - shp->ds_paddr;
 547                        dlthis->allocated_secn_count += 1;
 548                }               /* allocate target storage */
 549                shp += 1;
 550                asecs += 1;
 551        }
 552#if BITS_PER_AU <= BITS_PER_BYTE
 553        dlthis->debug_string_size +=
 554            strlen(dlthis->str_head + dlthis->debug_string_size) + 1;
 555#endif
 556}                               /* allocate sections */
 557
 558/*************************************************************************
 559 * Procedure section_table_free
 560 *
 561 * Parameters:
 562 *      none
 563 *
 564 * Effect:
 565 *      Frees any state used by the symbol table.
 566 *
 567 * WARNING:
 568 *      This routine is not allowed to declare errors!
 569 *********************************************************************** */
 570static void section_table_free(struct dload_state *dlthis)
 571{
 572        struct doff_scnhdr_t *shp;
 573
 574        shp = dlthis->sect_hdrs;
 575        if (shp)
 576                dlthis->mysym->dload_deallocate(dlthis->mysym, shp);
 577
 578}                               /* section_table_free */
 579
 580/*************************************************************************
 581 * Procedure dload_strings
 582 *
 583 * Parameters:
 584 *  sec_names_only   If true only read in the "section names"
 585 *                   portion of the string table
 586 *
 587 * Effect:
 588 *      Loads the DOFF string table into memory. DOFF keeps all strings in a
 589 * big unsorted array.  We just read that array into memory in bulk.
 590 *********************************************************************** */
 591static const char stringtbl[] = { "string table" };
 592
 593void dload_strings(struct dload_state *dlthis, bool sec_names_only)
 594{
 595        u32 ssiz;
 596        char *strbuf;
 597
 598        if (sec_names_only) {
 599                ssiz = BYTE_TO_HOST(DOFF_ALIGN
 600                                    (dlthis->dfile_hdr.df_scn_name_size));
 601        } else {
 602                ssiz = BYTE_TO_HOST(DOFF_ALIGN
 603                                    (dlthis->dfile_hdr.df_strtab_size));
 604        }
 605        if (ssiz == 0)
 606                return;
 607
 608        /* get some memory for the string table */
 609#if BITS_PER_AU > BITS_PER_BYTE
 610        strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz +
 611                                                       dlthis->dfile_hdr.
 612                                                       df_max_str_len);
 613#else
 614        strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz);
 615#endif
 616        if (strbuf == NULL) {
 617                DL_ERROR(err_alloc, ssiz);
 618                return;
 619        }
 620        dlthis->str_head = strbuf;
 621#if BITS_PER_AU > BITS_PER_BYTE
 622        dlthis->str_temp = strbuf + ssiz;
 623#endif
 624        /* read in the strings and verify them */
 625        if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf,
 626                                                 ssiz)) != ssiz) {
 627                DL_ERROR(readstrm, stringtbl);
 628        }
 629        /* if we need to fix up byte order, do it now */
 630#ifndef _BIG_ENDIAN
 631        if (dlthis->reorder_map)
 632                dload_reorder(strbuf, ssiz, dlthis->reorder_map);
 633
 634        if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) !=
 635                                  dlthis->verify.dv_str_tab_checksum)) {
 636                DL_ERROR(err_checksum, stringtbl);
 637        }
 638#else
 639        if (dlthis->dfile_hdr.df_byte_reshuffle !=
 640            HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
 641                /* put strings in big-endian order, not in PC order */
 642                dload_reorder(strbuf, ssiz,
 643                              HOST_BYTE_ORDER(dlthis->
 644                                              dfile_hdr.df_byte_reshuffle));
 645        }
 646        if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) !=
 647                                  dlthis->verify.dv_str_tab_checksum)) {
 648                DL_ERROR(err_checksum, stringtbl);
 649        }
 650#endif
 651}                               /* dload_strings */
 652
 653/*************************************************************************
 654 * Procedure string_table_free
 655 *
 656 * Parameters:
 657 *      none
 658 *
 659 * Effect:
 660 *      Frees any state used by the string table.
 661 *
 662 * WARNING:
 663 *      This routine is not allowed to declare errors!
 664 ************************************************************************ */
 665static void string_table_free(struct dload_state *dlthis)
 666{
 667        if (dlthis->str_head)
 668                dlthis->mysym->dload_deallocate(dlthis->mysym,
 669                                                dlthis->str_head);
 670
 671}                               /* string_table_free */
 672
 673/*
 674 * Symbol Table Maintenance Functions
 675 *
 676 * COFF symbols are read by dload_symbols(), which is called after
 677 * sections have been allocated.  Symbols which might be used in
 678 * relocation (ie, not debug info) are retained in an internal temporary
 679 * compressed table (type local_symbol). A particular symbol is recovered
 680 * by index by calling dload_find_symbol().  dload_find_symbol
 681 * reconstructs a more explicit representation (type SLOTVEC) which is
 682 * used by reloc.c
 683 */
 684/* real size of debug header */
 685#define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect))
 686
 687static const char sym_errid[] = { "symbol" };
 688
 689/**************************************************************************
 690 * Procedure dload_symbols
 691 *
 692 * Parameters:
 693 *      none
 694 *
 695 * Effect:
 696 *      Reads in symbols and retains ones that might be needed for relocation
 697 * purposes.
 698 *********************************************************************** */
 699/* size of symbol buffer no bigger than target data buffer, to limit stack
 700 * usage */
 701#define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\
 702                        sizeof(struct doff_syment_t))
 703
 704static void dload_symbols(struct dload_state *dlthis)
 705{
 706        u32 sym_count, siz, dsiz, symbols_left;
 707        u32 checks;
 708        struct local_symbol *sp;
 709        struct dynload_symbol *symp;
 710        struct dynload_symbol *newsym;
 711        struct doff_syment_t *my_sym_buf;
 712
 713        sym_count = dlthis->dfile_hdr.df_no_syms;
 714        if (sym_count == 0)
 715                return;
 716
 717        /*
 718         * We keep a local symbol table for all of the symbols in the input.
 719         * This table contains only section & value info, as we do not have
 720         * to do any name processing for locals.  We reuse this storage
 721         * as a temporary for .dllview record construction.
 722         * Allocate storage for the whole table.  Add 1 to the section count
 723         * in case a trampoline section is auto-generated as well as the
 724         * size of the trampoline section name so DLLView doesn't get lost.
 725         */
 726
 727        siz = sym_count * sizeof(struct local_symbol);
 728        dsiz = DBG_HDR_SIZE +
 729            (sizeof(struct dll_sect) * dlthis->allocated_secn_count) +
 730            BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1);
 731        if (dsiz > siz)
 732                siz = dsiz;     /* larger of symbols and .dllview temp */
 733        sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
 734                                                                  siz);
 735        if (!sp) {
 736                DL_ERROR(err_alloc, siz);
 737                return;
 738        }
 739        dlthis->local_symtab = sp;
 740        /* Read the symbols in the input, store them in the table, and post any
 741         * globals to the global symbol table.  In the process, externals
 742         become defined from the global symbol table */
 743        checks = dlthis->verify.dv_sym_tab_checksum;
 744        symbols_left = sym_count;
 745
 746        my_sym_buf = kzalloc(sizeof(*my_sym_buf) * MY_SYM_BUF_SIZ, GFP_KERNEL);
 747        if (!my_sym_buf)
 748                return;
 749
 750        do {                    /* read all symbols */
 751                char *sname;
 752                u32 val;
 753                s32 delta;
 754                struct doff_syment_t *input_sym;
 755                unsigned syms_in_buf;
 756
 757                input_sym = my_sym_buf;
 758                syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ?
 759                    MY_SYM_BUF_SIZ : symbols_left;
 760                siz = syms_in_buf * sizeof(struct doff_syment_t);
 761                if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) !=
 762                    siz) {
 763                        DL_ERROR(readstrm, sym_errid);
 764                        goto free_sym_buf;
 765                }
 766                if (dlthis->reorder_map)
 767                        dload_reorder(input_sym, siz, dlthis->reorder_map);
 768
 769                checks += dload_checksum(input_sym, siz);
 770                do {            /* process symbols in buffer */
 771                        symbols_left -= 1;
 772                        /* attempt to derive the name of this symbol */
 773                        sname = NULL;
 774                        if (input_sym->dn_offset > 0) {
 775#if BITS_PER_AU <= BITS_PER_BYTE
 776                                if ((u32) input_sym->dn_offset <
 777                                    dlthis->dfile_hdr.df_strtab_size)
 778                                        sname = dlthis->str_head +
 779                                            BYTE_TO_HOST(input_sym->dn_offset);
 780                                else
 781                                        dload_error(dlthis,
 782                                                    "Bad name offset in symbol "
 783                                                    " %d", symbols_left);
 784#else
 785                                sname = unpack_name(dlthis,
 786                                                    input_sym->dn_offset);
 787#endif
 788                        }
 789                        val = input_sym->dn_value;
 790                        delta = 0;
 791                        sp->sclass = input_sym->dn_sclass;
 792                        sp->secnn = input_sym->dn_scnum;
 793                        /* if this is an undefined symbol,
 794                         * define it (or fail) now */
 795                        if (sp->secnn == DN_UNDEF) {
 796                                /* pointless for static undefined */
 797                                if (input_sym->dn_sclass != DN_EXT)
 798                                        goto loop_cont;
 799
 800                                /* try to define symbol from previously
 801                                 * loaded images */
 802                                symp = dlthis->mysym->find_matching_symbol
 803                                    (dlthis->mysym, sname);
 804                                if (!symp) {
 805                                        DL_ERROR
 806                                            ("Undefined external symbol %s",
 807                                             sname);
 808                                        goto loop_cont;
 809                                }
 810                                val = delta = symp->value;
 811#ifdef ENABLE_TRAMP_DEBUG
 812                                dload_syms_error(dlthis->mysym,
 813                                                 "===> ext sym [%s] at %x",
 814                                                 sname, val);
 815#endif
 816
 817                                goto loop_cont;
 818                        }
 819                        /* symbol defined by this module */
 820                        if (sp->secnn > 0) {
 821                                /* symbol references a section */
 822                                if ((unsigned)sp->secnn <=
 823                                    dlthis->allocated_secn_count) {
 824                                        /* section was allocated */
 825                                        struct doff_scnhdr_t *srefp =
 826                                            &dlthis->sect_hdrs[sp->secnn - 1];
 827
 828                                        if (input_sym->dn_sclass ==
 829                                            DN_STATLAB ||
 830                                            input_sym->dn_sclass == DN_EXTLAB) {
 831                                                /* load */
 832                                                delta = srefp->ds_vaddr;
 833                                        } else {
 834                                                /* run */
 835                                                delta = srefp->ds_paddr;
 836                                        }
 837                                        val += delta;
 838                                }
 839                                goto loop_itr;
 840                        }
 841                        /* This symbol is an absolute symbol */
 842                        if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) ||
 843                                                    (sp->sclass ==
 844                                                     DN_EXTLAB))) {
 845                                symp =
 846                                    dlthis->mysym->find_matching_symbol(dlthis->
 847                                                                        mysym,
 848                                                                        sname);
 849                                if (!symp)
 850                                        goto loop_itr;
 851                                /* This absolute symbol is already defined. */
 852                                if (symp->value == input_sym->dn_value) {
 853                                        /* If symbol values are equal, continue
 854                                         * but don't add to the global symbol
 855                                         * table */
 856                                        sp->value = val;
 857                                        sp->delta = delta;
 858                                        sp += 1;
 859                                        input_sym += 1;
 860                                        continue;
 861                                } else {
 862                                        /* If symbol values are not equal,
 863                                         * return with redefinition error */
 864                                        DL_ERROR("Absolute symbol %s is "
 865                                                 "defined multiple times with "
 866                                                 "different values", sname);
 867                                        goto free_sym_buf;
 868                                }
 869                        }
 870loop_itr:
 871                        /* if this is a global symbol, post it to the
 872                         * global table */
 873                        if (input_sym->dn_sclass == DN_EXT ||
 874                            input_sym->dn_sclass == DN_EXTLAB) {
 875                                /* Keep this global symbol for subsequent
 876                                 * modules. Don't complain on error, to allow
 877                                 * symbol API to suppress global symbols */
 878                                if (!sname)
 879                                        goto loop_cont;
 880
 881                                newsym = dlthis->mysym->add_to_symbol_table
 882                                    (dlthis->mysym, sname,
 883                                     (unsigned)dlthis->myhandle);
 884                                if (newsym)
 885                                        newsym->value = val;
 886
 887                        }       /* global */
 888loop_cont:
 889                        sp->value = val;
 890                        sp->delta = delta;
 891                        sp += 1;
 892                        input_sym += 1;
 893                } while ((syms_in_buf -= 1) > 0);       /* process sym in buf */
 894        } while (symbols_left > 0);     /* read all symbols */
 895        if (~checks)
 896                dload_error(dlthis, "Checksum of symbols failed");
 897
 898free_sym_buf:
 899        kfree(my_sym_buf);
 900        return;
 901}                               /* dload_symbols */
 902
 903/*****************************************************************************
 904 * Procedure symbol_table_free
 905 *
 906 * Parameters:
 907 *      none
 908 *
 909 * Effect:
 910 *      Frees any state used by the symbol table.
 911 *
 912 * WARNING:
 913 *      This routine is not allowed to declare errors!
 914 **************************************************************************** */
 915static void symbol_table_free(struct dload_state *dlthis)
 916{
 917        if (dlthis->local_symtab) {
 918                if (dlthis->dload_errcount) {   /* blow off our symbols */
 919                        dlthis->mysym->purge_symbol_table(dlthis->mysym,
 920                                                          (unsigned)
 921                                                          dlthis->myhandle);
 922                }
 923                dlthis->mysym->dload_deallocate(dlthis->mysym,
 924                                                dlthis->local_symtab);
 925        }
 926}                               /* symbol_table_free */
 927
 928/* .cinit Processing
 929 *
 930 * The dynamic loader does .cinit interpretation.  cload_cinit()
 931 * acts as a special write-to-target function, in that it takes relocated
 932 * data from the normal data flow, and interprets it as .cinit actions.
 933 * Because the normal data flow does not  necessarily process the whole
 934 * .cinit section in one buffer, cload_cinit() must be prepared to
 935 * interpret the data piecemeal.  A state machine is used for this
 936 * purpose.
 937 */
 938
 939/* The following are only for use by reloc.c and things it calls */
 940static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0,
 941        (ldr_addr)-1, 0, DLOAD_BSS, 0
 942};
 943
 944/*************************************************************************
 945 * Procedure cload_cinit
 946 *
 947 * Parameters:
 948 *      ipacket         Pointer to data packet to be loaded
 949 *
 950 * Effect:
 951 *      Interprets the data in the buffer as .cinit data, and performs the
 952 * appropriate initializations.
 953 *********************************************************************** */
 954static void cload_cinit(struct dload_state *dlthis,
 955                        struct image_packet_t *ipacket)
 956{
 957#if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16
 958        s32 init_count, left;
 959#else
 960        s16 init_count, left;
 961#endif
 962        unsigned char *pktp = ipacket->img_data;
 963        unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size);
 964        int temp;
 965        ldr_addr atmp;
 966        struct ldr_section_info cinit_info;
 967
 968        /*  PROCESS ALL THE INITIALIZATION RECORDS THE BUFFER. */
 969        while (true) {
 970                left = pktend - pktp;
 971                switch (dlthis->cinit_state) {
 972                case CI_COUNT:  /* count field */
 973                        if (left < TDATA_TO_HOST(CINIT_COUNT))
 974                                goto loopexit;
 975                        temp = dload_unpack(dlthis, (tgt_au_t *) pktp,
 976                                            CINIT_COUNT * TDATA_AU_BITS, 0,
 977                                            ROP_SGN);
 978                        pktp += TDATA_TO_HOST(CINIT_COUNT);
 979                        /* negative signifies BSS table, zero means done */
 980                        if (temp <= 0) {
 981                                dlthis->cinit_state = CI_DONE;
 982                                break;
 983                        }
 984                        dlthis->cinit_count = temp;
 985                        dlthis->cinit_state = CI_ADDRESS;
 986                        break;
 987#if CINIT_ALIGN < CINIT_ADDRESS
 988                case CI_PARTADDRESS:
 989                        pktp -= TDATA_TO_HOST(CINIT_ALIGN);
 990                        /* back up pointer into space courtesy of caller */
 991                        *(uint16_t *) pktp = dlthis->cinit_addr;
 992                        /* stuff in saved bits  !! FALL THRU !! */
 993#endif
 994                case CI_ADDRESS:        /* Address field for a copy packet */
 995                        if (left < TDATA_TO_HOST(CINIT_ADDRESS)) {
 996#if CINIT_ALIGN < CINIT_ADDRESS
 997                                if (left == TDATA_TO_HOST(CINIT_ALIGN)) {
 998                                        /* address broken into halves */
 999                                        dlthis->cinit_addr = *(uint16_t *) pktp;
1000                                        /* remember 1st half */
1001                                        dlthis->cinit_state = CI_PARTADDRESS;
1002                                        left = 0;
1003                                }
1004#endif
1005                                goto loopexit;
1006                        }
1007                        atmp = dload_unpack(dlthis, (tgt_au_t *) pktp,
1008                                            CINIT_ADDRESS * TDATA_AU_BITS, 0,
1009                                            ROP_UNS);
1010                        pktp += TDATA_TO_HOST(CINIT_ADDRESS);
1011#if CINIT_PAGE_BITS > 0
1012                        dlthis->cinit_page = atmp &
1013                            ((1 << CINIT_PAGE_BITS) - 1);
1014                        atmp >>= CINIT_PAGE_BITS;
1015#else
1016                        dlthis->cinit_page = CINIT_DEFAULT_PAGE;
1017#endif
1018                        dlthis->cinit_addr = atmp;
1019                        dlthis->cinit_state = CI_COPY;
1020                        break;
1021                case CI_COPY:   /* copy bits to the target */
1022                        init_count = HOST_TO_TDATA(left);
1023                        if (init_count > dlthis->cinit_count)
1024                                init_count = dlthis->cinit_count;
1025                        if (init_count == 0)
1026                                goto loopexit;  /* get more bits */
1027                        cinit_info = cinit_info_init;
1028                        cinit_info.page = dlthis->cinit_page;
1029                        if (!dlthis->myio->writemem(dlthis->myio, pktp,
1030                                                   TDATA_TO_TADDR
1031                                                   (dlthis->cinit_addr),
1032                                                   &cinit_info,
1033                                                   TDATA_TO_HOST(init_count))) {
1034                                dload_error(dlthis, initfail, "write",
1035                                            dlthis->cinit_addr);
1036                        }
1037                        dlthis->cinit_count -= init_count;
1038                        if (dlthis->cinit_count <= 0) {
1039                                dlthis->cinit_state = CI_COUNT;
1040                                init_count = (init_count + CINIT_ALIGN - 1) &
1041                                    -CINIT_ALIGN;
1042                                /* align to next init */
1043                        }
1044                        pktp += TDATA_TO_HOST(init_count);
1045                        dlthis->cinit_addr += init_count;
1046                        break;
1047                case CI_DONE:   /* no more .cinit to do */
1048                        return;
1049                }               /* switch (cinit_state) */
1050        }                       /* while */
1051
1052loopexit:
1053        if (left > 0) {
1054                dload_error(dlthis, "%d bytes left over in cinit packet", left);
1055                dlthis->cinit_state = CI_DONE;  /* left over bytes are bad */
1056        }
1057}                               /* cload_cinit */
1058
1059/*      Functions to interface to reloc.c
1060 *
1061 * reloc.c is the relocation module borrowed from the linker, with
1062 * minimal (we hope) changes for our purposes.  cload_sect_data() invokes
1063 * this module on a section to relocate and load the image data for that
1064 * section.  The actual read and write actions are supplied by the global
1065 * routines below.
1066 */
1067
1068/************************************************************************
1069 * Procedure relocate_packet
1070 *
1071 * Parameters:
1072 *      ipacket         Pointer to an image packet to relocate
1073 *
1074 * Effect:
1075 *      Performs the required relocations on the packet.  Returns a checksum
1076 * of the relocation operations.
1077 *********************************************************************** */
1078#define MY_RELOC_BUF_SIZ 8
1079/* careful! exists at the same time as the image buffer */
1080static int relocate_packet(struct dload_state *dlthis,
1081                           struct image_packet_t *ipacket,
1082                           u32 *checks, bool *tramps_generated)
1083{
1084        u32 rnum;
1085        *tramps_generated = false;
1086
1087        rnum = ipacket->num_relocs;
1088        do {                    /* all relocs */
1089                unsigned rinbuf;
1090                int siz;
1091                struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ];
1092                rp = rrec;
1093                rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum;
1094                siz = rinbuf * sizeof(struct reloc_record_t);
1095                if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) {
1096                        DL_ERROR(readstrm, "relocation");
1097                        return 0;
1098                }
1099                /* reorder the bytes if need be */
1100                if (dlthis->reorder_map)
1101                        dload_reorder(rp, siz, dlthis->reorder_map);
1102
1103                *checks += dload_checksum(rp, siz);
1104                do {
1105                        /* perform the relocation operation */
1106                        dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data,
1107                                       rp, tramps_generated, false);
1108                        rp += 1;
1109                        rnum -= 1;
1110                } while ((rinbuf -= 1) > 0);
1111        } while (rnum > 0);     /* all relocs */
1112        /* If trampoline(s) were generated, we need to do an update of the
1113         * trampoline copy of the packet since a 2nd phase relo will be done
1114         * later. */
1115        if (*tramps_generated == true) {
1116                dload_tramp_pkt_udpate(dlthis,
1117                                       (dlthis->image_secn -
1118                                        dlthis->ldr_sections),
1119                                       dlthis->image_offset, ipacket);
1120        }
1121
1122        return 1;
1123}                               /* dload_read_reloc */
1124
1125#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
1126
1127/* VERY dangerous */
1128static const char imagepak[] = { "image packet" };
1129
1130struct img_buffer {
1131        struct image_packet_t ipacket;
1132        u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)];
1133};
1134
1135/*************************************************************************
1136 * Procedure dload_data
1137 *
1138 * Parameters:
1139 *      none
1140 *
1141 * Effect:
1142 *      Read image data from input file, relocate it, and download it to the
1143 *      target.
1144 *********************************************************************** */
1145static void dload_data(struct dload_state *dlthis)
1146{
1147        u16 curr_sect;
1148        struct doff_scnhdr_t *sptr = dlthis->sect_hdrs;
1149        struct ldr_section_info *lptr = dlthis->ldr_sections;
1150        struct img_buffer *ibuf;
1151        u8 *dest;
1152
1153        /* Indicates whether CINIT processing has occurred */
1154        bool cinit_processed = false;
1155
1156        ibuf = kzalloc(sizeof(*ibuf), GFP_KERNEL);
1157        if (!ibuf)
1158                return;
1159
1160        /* Loop through the sections and load them one at a time.
1161         */
1162        for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns;
1163             curr_sect += 1) {
1164                if (ds_needs_download(sptr)) {
1165                        s32 nip;
1166                        ldr_addr image_offset = 0;
1167                        /* set relocation info for this section */
1168                        if (curr_sect < dlthis->allocated_secn_count)
1169                                dlthis->delta_runaddr = sptr->ds_paddr;
1170                        else {
1171                                lptr = (struct ldr_section_info *)sptr;
1172                                dlthis->delta_runaddr = 0;
1173                        }
1174                        dlthis->image_secn = lptr;
1175#if BITS_PER_AU > BITS_PER_BYTE
1176                        lptr->name = unpack_name(dlthis, sptr->ds_offset);
1177#endif
1178                        nip = sptr->ds_nipacks;
1179                        while ((nip -= 1) >= 0) {       /* process packets */
1180
1181                                s32 ipsize;
1182                                u32 checks;
1183                                bool tramp_generated = false;
1184
1185                                /* get the fixed header bits */
1186                                if (dlthis->strm->read_buffer(dlthis->strm,
1187                                                              &ibuf->ipacket,
1188                                                              IPH_SIZE) !=
1189                                    IPH_SIZE) {
1190                                        DL_ERROR(readstrm, imagepak);
1191                                        goto free_ibuf;
1192                                }
1193                                /* reorder the header if need be */
1194                                if (dlthis->reorder_map) {
1195                                        dload_reorder(&ibuf->ipacket, IPH_SIZE,
1196                                                      dlthis->reorder_map);
1197                                }
1198                                /* now read the rest of the packet */
1199                                ipsize =
1200                                    BYTE_TO_HOST(DOFF_ALIGN
1201                                                 (ibuf->ipacket.packet_size));
1202                                if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
1203                                        DL_ERROR("Bad image packet size %d",
1204                                                 ipsize);
1205                                        goto free_ibuf;
1206                                }
1207                                dest = ibuf->bufr;
1208                                /* End of determination */
1209
1210                                if (dlthis->strm->read_buffer(dlthis->strm,
1211                                                              ibuf->bufr,
1212                                                              ipsize) !=
1213                                    ipsize) {
1214                                        DL_ERROR(readstrm, imagepak);
1215                                        goto free_ibuf;
1216                                }
1217                                ibuf->ipacket.img_data = dest;
1218
1219                                /* reorder the bytes if need be */
1220#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
1221                                if (dlthis->reorder_map) {
1222                                        dload_reorder(dest, ipsize,
1223                                                      dlthis->reorder_map);
1224                                }
1225                                checks = dload_checksum(dest, ipsize);
1226#else
1227                                if (dlthis->dfile_hdr.df_byte_reshuffle !=
1228                                    TARGET_ORDER(REORDER_MAP
1229                                                 (BYTE_RESHUFFLE_VALUE))) {
1230                                        /* put image bytes in big-endian order,
1231                                         * not PC order */
1232                                        dload_reorder(dest, ipsize,
1233                                                      TARGET_ORDER
1234                                                      (dlthis->dfile_hdr.
1235                                                       df_byte_reshuffle));
1236                                }
1237#if TARGET_AU_BITS > 8
1238                                checks = dload_reverse_checksum16(dest, ipsize);
1239#else
1240                                checks = dload_reverse_checksum(dest, ipsize);
1241#endif
1242#endif
1243
1244                                checks += dload_checksum(&ibuf->ipacket,
1245                                                         IPH_SIZE);
1246                                /* relocate the image bits as needed */
1247                                if (ibuf->ipacket.num_relocs) {
1248                                        dlthis->image_offset = image_offset;
1249                                        if (!relocate_packet(dlthis,
1250                                                             &ibuf->ipacket,
1251                                                             &checks,
1252                                                             &tramp_generated))
1253                                                goto free_ibuf; /* error */
1254                                }
1255                                if (~checks)
1256                                        DL_ERROR(err_checksum, imagepak);
1257                                /* Only write the result to the target if no
1258                                 * trampoline was generated.  Otherwise it
1259                                 *will be done during trampoline finalize. */
1260
1261                                if (tramp_generated == false) {
1262
1263                                        /* stuff the result into target
1264                                         * memory */
1265                                        if (dload_check_type(sptr,
1266                                                DLOAD_CINIT)) {
1267                                                cload_cinit(dlthis,
1268                                                            &ibuf->ipacket);
1269                                                cinit_processed = true;
1270                                        } else {
1271                                                /* FIXME */
1272                                                if (!dlthis->myio->
1273                                                    writemem(dlthis->
1274                                                        myio,
1275                                                        ibuf->bufr,
1276                                                        lptr->
1277                                                        load_addr +
1278                                                        image_offset,
1279                                                        lptr,
1280                                                        BYTE_TO_HOST
1281                                                        (ibuf->
1282                                                        ipacket.
1283                                                        packet_size))) {
1284                                                        DL_ERROR
1285                                                          ("Write to "
1286                                                          FMT_UI32
1287                                                          " failed",
1288                                                          lptr->
1289                                                          load_addr +
1290                                                          image_offset);
1291                                                }
1292                                        }
1293                                }
1294                                image_offset +=
1295                                    BYTE_TO_TADDR(ibuf->ipacket.packet_size);
1296                        }       /* process packets */
1297                        /* if this is a BSS section, we may want to fill it */
1298                        if (!dload_check_type(sptr, DLOAD_BSS))
1299                                goto loop_cont;
1300
1301                        if (!(dlthis->myoptions & DLOAD_INITBSS))
1302                                goto loop_cont;
1303
1304                        if (cinit_processed) {
1305                                /* Don't clear BSS after load-time
1306                                 * initialization */
1307                                DL_ERROR
1308                                    ("Zero-initialization at " FMT_UI32
1309                                     " after " "load-time initialization!",
1310                                     lptr->load_addr);
1311                                goto loop_cont;
1312                        }
1313                        /* fill the .bss area */
1314                        dlthis->myio->fillmem(dlthis->myio,
1315                                              TADDR_TO_HOST(lptr->load_addr),
1316                                              lptr, TADDR_TO_HOST(lptr->size),
1317                                              DLOAD_FILL_BSS);
1318                        goto loop_cont;
1319                }
1320                /* if DS_DOWNLOAD_MASK */
1321                /* If not loading, but BSS, zero initialize */
1322                if (!dload_check_type(sptr, DLOAD_BSS))
1323                        goto loop_cont;
1324
1325                if (!(dlthis->myoptions & DLOAD_INITBSS))
1326                        goto loop_cont;
1327
1328                if (curr_sect >= dlthis->allocated_secn_count)
1329                        lptr = (struct ldr_section_info *)sptr;
1330
1331                if (cinit_processed) {
1332                        /*Don't clear BSS after load-time initialization */
1333                        DL_ERROR("Zero-initialization at " FMT_UI32
1334                                 " attempted after "
1335                                 "load-time initialization!", lptr->load_addr);
1336                        goto loop_cont;
1337                }
1338                /* fill the .bss area */
1339                dlthis->myio->fillmem(dlthis->myio,
1340                                      TADDR_TO_HOST(lptr->load_addr), lptr,
1341                                      TADDR_TO_HOST(lptr->size),
1342                                      DLOAD_FILL_BSS);
1343loop_cont:
1344                sptr += 1;
1345                lptr += 1;
1346        }                       /* load sections */
1347
1348        /*  Finalize any trampolines that were created during the load */
1349        if (dload_tramp_finalize(dlthis) == 0) {
1350                DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32
1351                         ") failed", dlthis->tramp.tramp_sect_next_addr);
1352        }
1353free_ibuf:
1354        kfree(ibuf);
1355        return;
1356}                               /* dload_data */
1357
1358/*************************************************************************
1359 * Procedure dload_reorder
1360 *
1361 * Parameters:
1362 *      data    32-bit aligned pointer to data to be byte-swapped
1363 *      dsiz    size of the data to be reordered in sizeof() units.
1364 *      map             32-bit map defining how to reorder the data.  Value
1365 *                      must be REORDER_MAP() of some permutation
1366 *                      of 0x00 01 02 03
1367 *
1368 * Effect:
1369 *      Re-arranges the bytes in each word according to the map specified.
1370 *
1371 *********************************************************************** */
1372/* mask for byte shift count */
1373#define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE)
1374
1375void dload_reorder(void *data, int dsiz, unsigned int map)
1376{
1377        register u32 tmp, tmap, datv;
1378        u32 *dp = (u32 *) data;
1379
1380        map <<= LOG_BITS_PER_BYTE;      /* align map with SHIFT_COUNT_MASK */
1381        do {
1382                tmp = 0;
1383                datv = *dp;
1384                tmap = map;
1385                do {
1386                        tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK);
1387                        tmap >>= BITS_PER_BYTE;
1388                } while (datv >>= BITS_PER_BYTE);
1389                *dp++ = tmp;
1390        } while ((dsiz -= sizeof(u32)) > 0);
1391}                               /* dload_reorder */
1392
1393/*************************************************************************
1394 * Procedure dload_checksum
1395 *
1396 * Parameters:
1397 *      data    32-bit aligned pointer to data to be checksummed
1398 *      siz             size of the data to be checksummed in sizeof() units.
1399 *
1400 * Effect:
1401 *      Returns a checksum of the specified block
1402 *
1403 *********************************************************************** */
1404u32 dload_checksum(void *data, unsigned siz)
1405{
1406        u32 sum;
1407        u32 *dp;
1408        int left;
1409
1410        sum = 0;
1411        dp = (u32 *) data;
1412        for (left = siz; left > 0; left -= sizeof(u32))
1413                sum += *dp++;
1414        return sum;
1415}                               /* dload_checksum */
1416
1417#if HOST_ENDIANNESS
1418/*************************************************************************
1419 * Procedure dload_reverse_checksum
1420 *
1421 * Parameters:
1422 *      data    32-bit aligned pointer to data to be checksummed
1423 *      siz             size of the data to be checksummed in sizeof() units.
1424 *
1425 * Effect:
1426 *      Returns a checksum of the specified block, which is assumed to be bytes
1427 * in big-endian order.
1428 *
1429 * Notes:
1430 *      In a big-endian host, things like the string table are stored as bytes
1431 * in host order. But dllcreate always checksums in little-endian order.
1432 * It is most efficient to just handle the difference a word at a time.
1433 *
1434 ********************************************************************** */
1435u32 dload_reverse_checksum(void *data, unsigned siz)
1436{
1437        u32 sum, temp;
1438        u32 *dp;
1439        int left;
1440
1441        sum = 0;
1442        dp = (u32 *) data;
1443
1444        for (left = siz; left > 0; left -= sizeof(u32)) {
1445                temp = *dp++;
1446                sum += temp << BITS_PER_BYTE * 3;
1447                sum += temp >> BITS_PER_BYTE * 3;
1448                sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE);
1449                sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE;
1450        }
1451
1452        return sum;
1453}                               /* dload_reverse_checksum */
1454
1455#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
1456u32 dload_reverse_checksum16(void *data, unsigned siz)
1457{
1458        uint_fast32_t sum, temp;
1459        u32 *dp;
1460        int left;
1461
1462        sum = 0;
1463        dp = (u32 *) data;
1464
1465        for (left = siz; left > 0; left -= sizeof(u32)) {
1466                temp = *dp++;
1467                sum += temp << BITS_PER_BYTE * 2;
1468                sum += temp >> BITS_PER_BYTE * 2;
1469        }
1470
1471        return sum;
1472}                               /* dload_reverse_checksum16 */
1473#endif
1474#endif
1475
1476/*************************************************************************
1477 * Procedure swap_words
1478 *
1479 * Parameters:
1480 *      data    32-bit aligned pointer to data to be swapped
1481 *      siz     size of the data to be swapped.
1482 *      bitmap  Bit map of how to swap each 32-bit word; 1 => 2 shorts,
1483 *              0 => 1 long
1484 *
1485 * Effect:
1486 *      Swaps the specified data according to the specified map
1487 *
1488 *********************************************************************** */
1489static void swap_words(void *data, unsigned siz, unsigned bitmap)
1490{
1491        register int i;
1492#if TARGET_AU_BITS < 16
1493        register u16 *sp;
1494#endif
1495        register u32 *lp;
1496
1497        siz /= sizeof(u16);
1498
1499#if TARGET_AU_BITS < 16
1500        /* pass 1: do all the bytes */
1501        i = siz;
1502        sp = (u16 *) data;
1503        do {
1504                register u16 tmp;
1505                tmp = *sp;
1506                *sp++ = SWAP16BY8(tmp);
1507        } while ((i -= 1) > 0);
1508#endif
1509
1510#if TARGET_AU_BITS < 32
1511        /* pass 2: fixup the 32-bit words */
1512        i = siz >> 1;
1513        lp = (u32 *) data;
1514        do {
1515                if ((bitmap & 1) == 0) {
1516                        register u32 tmp;
1517                        tmp = *lp;
1518                        *lp = SWAP32BY16(tmp);
1519                }
1520                lp += 1;
1521                bitmap >>= 1;
1522        } while ((i -= 1) > 0);
1523#endif
1524}                               /* swap_words */
1525
1526/*************************************************************************
1527 * Procedure copy_tgt_strings
1528 *
1529 * Parameters:
1530 *      dstp            Destination address.  Assumed to be 32-bit aligned
1531 *      srcp            Source address.  Assumed to be 32-bit aligned
1532 *      charcount       Number of characters to copy.
1533 *
1534 * Effect:
1535 *      Copies strings from the source (which is in usual .dof file order on
1536 * the loading processor) to the destination buffer (which should be in proper
1537 * target addressable unit order).  Makes sure the last string in the
1538 * buffer is NULL terminated (for safety).
1539 * Returns the first unused destination address.
1540 *********************************************************************** */
1541static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount)
1542{
1543        register tgt_au_t *src = (tgt_au_t *) srcp;
1544        register tgt_au_t *dst = (tgt_au_t *) dstp;
1545        register int cnt = charcount;
1546        do {
1547#if TARGET_AU_BITS <= BITS_PER_AU
1548                /* byte-swapping issues may exist for strings on target */
1549                *dst++ = *src++;
1550#else
1551                *dst++ = *src++;
1552#endif
1553        } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0);
1554        /*apply force to make sure that the string table has null terminator */
1555#if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE)
1556        dst[-1] = 0;
1557#else
1558        /* little endian */
1559        dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1;
1560#endif
1561        return (char *)dst;
1562}                               /* copy_tgt_strings */
1563
1564/*************************************************************************
1565 * Procedure init_module_handle
1566 *
1567 * Parameters:
1568 *      none
1569 *
1570 * Effect:
1571 *      Initializes the module handle we use to enable unloading, and installs
1572 * the debug information required by the target.
1573 *
1574 * Notes:
1575 * The handle returned from dynamic_load_module needs to encapsulate all the
1576 * allocations done for the module, and enable them plus the modules symbols to
1577 * be deallocated.
1578 *
1579 *********************************************************************** */
1580#ifndef _BIG_ENDIAN
1581static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1582        (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0
1583};
1584#else
1585static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1586        (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0
1587};
1588#endif
1589static void init_module_handle(struct dload_state *dlthis)
1590{
1591        struct my_handle *hndl;
1592        u16 curr_sect;
1593        struct ldr_section_info *asecs;
1594        struct dll_module *dbmod;
1595        struct dll_sect *dbsec;
1596        struct dbg_mirror_root *mlist;
1597        register char *cp;
1598        struct modules_header mhdr;
1599        struct ldr_section_info dllview_info;
1600        struct dynload_symbol *debug_mirror_sym;
1601        hndl = dlthis->myhandle;
1602        if (!hndl)
1603                return;         /* must be errors detected, so forget it */
1604
1605        /*  Store the section count */
1606        hndl->secn_count = dlthis->allocated_secn_count;
1607
1608        /*  If a trampoline section was created, add it in */
1609        if (dlthis->tramp.tramp_sect_next_addr != 0)
1610                hndl->secn_count += 1;
1611
1612        hndl->secn_count = hndl->secn_count << 1;
1613
1614        hndl->secn_count = dlthis->allocated_secn_count << 1;
1615#ifndef TARGET_ENDIANNESS
1616        if (dlthis->big_e_target)
1617                hndl->secn_count += 1;  /* flag for big-endian */
1618#endif
1619        if (dlthis->dload_errcount)
1620                return;         /* abandon if errors detected */
1621        /* Locate the symbol that names the header for the CCS debug list
1622           of modules. If not found, we just don't generate the debug record.
1623           If found, we create our modules list.  We make sure to create the
1624           loader_dllview_root even if there is no relocation info to record,
1625           just to try to put both symbols in the same symbol table and
1626           module. */
1627        debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
1628                                                        loader_dllview_root);
1629        if (!debug_mirror_sym) {
1630                struct dynload_symbol *dlmodsym;
1631                struct dbg_mirror_root *mlst;
1632
1633                /* our root symbol is not yet present;
1634                   check if we have DLModules defined */
1635                dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
1636                                                        LINKER_MODULES_HEADER);
1637                if (!dlmodsym)
1638                        return; /* no DLModules list so no debug info */
1639                /* if we have DLModules defined, construct our header */
1640                mlst = (struct dbg_mirror_root *)
1641                    dlthis->mysym->dload_allocate(dlthis->mysym,
1642                                                  sizeof(struct
1643                                                         dbg_mirror_root));
1644                if (!mlst) {
1645                        DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root));
1646                        return;
1647                }
1648                mlst->next = NULL;
1649                mlst->changes = 0;
1650                mlst->refcount = 0;
1651                mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value);
1652                /* add our root symbol */
1653                debug_mirror_sym = dlthis->mysym->add_to_symbol_table
1654                    (dlthis->mysym, loader_dllview_root,
1655                     (unsigned)dlthis->myhandle);
1656                if (!debug_mirror_sym) {
1657                        /* failed, recover memory */
1658                        dlthis->mysym->dload_deallocate(dlthis->mysym, mlst);
1659                        return;
1660                }
1661                debug_mirror_sym->value = (u32) mlst;
1662        }
1663        /* First create the DLLview record and stuff it into the buffer.
1664           Then write it to the DSP.  Record pertinent locations in our hndl,
1665           and add it to the per-processor list of handles with debug info. */
1666#ifndef DEBUG_HEADER_IN_LOADER
1667        mlist = (struct dbg_mirror_root *)debug_mirror_sym->value;
1668        if (!mlist)
1669                return;
1670#else
1671        mlist = (struct dbg_mirror_root *)&debug_list_header;
1672#endif
1673        hndl->dm.root = mlist;  /* set pointer to root into our handle */
1674        if (!dlthis->allocated_secn_count)
1675                return;         /* no load addresses to be recorded */
1676        /* reuse temporary symbol storage */
1677        dbmod = (struct dll_module *)dlthis->local_symtab;
1678        /* Create the DLLview record in the memory we retain for our handle */
1679        dbmod->num_sects = dlthis->allocated_secn_count;
1680        dbmod->timestamp = dlthis->verify.dv_timdat;
1681        dbmod->version = INIT_VERSION;
1682        dbmod->verification = VERIFICATION;
1683        asecs = dlthis->ldr_sections;
1684        dbsec = dbmod->sects;
1685        for (curr_sect = dlthis->allocated_secn_count;
1686             curr_sect > 0; curr_sect -= 1) {
1687                dbsec->sect_load_adr = asecs->load_addr;
1688                dbsec->sect_run_adr = asecs->run_addr;
1689                dbsec += 1;
1690                asecs += 1;
1691        }
1692
1693        /*  If a trampoline section was created go ahead and add its info */
1694        if (dlthis->tramp.tramp_sect_next_addr != 0) {
1695                dbmod->num_sects++;
1696                dbsec->sect_load_adr = asecs->load_addr;
1697                dbsec->sect_run_adr = asecs->run_addr;
1698                dbsec++;
1699                asecs++;
1700        }
1701
1702        /* now cram in the names */
1703        cp = copy_tgt_strings(dbsec, dlthis->str_head,
1704                              dlthis->debug_string_size);
1705
1706        /* If a trampoline section was created, add its name so DLLView
1707         * can show the user the section info. */
1708        if (dlthis->tramp.tramp_sect_next_addr != 0) {
1709                cp = copy_tgt_strings(cp,
1710                                      dlthis->tramp.final_string_table,
1711                                      strlen(dlthis->tramp.final_string_table) +
1712                                      1);
1713        }
1714
1715        /* round off the size of the debug record, and remember same */
1716        hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod);
1717        *cp = 0;                /* strictly to make our test harness happy */
1718        dllview_info = dllview_info_init;
1719        dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
1720        /* Initialize memory context to default heap */
1721        dllview_info.context = 0;
1722        hndl->dm.context = 0;
1723        /* fill in next pointer and size */
1724        if (mlist->next) {
1725                dbmod->next_module = TADDR_TO_TDATA(mlist->next->dm.dbthis);
1726                dbmod->next_module_size = mlist->next->dm.dbsiz;
1727        } else {
1728                dbmod->next_module_size = 0;
1729                dbmod->next_module = 0;
1730        }
1731        /* allocate memory for on-DSP DLLview debug record */
1732        if (!dlthis->myalloc)
1733                return;
1734        if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info,
1735                                             HOST_TO_TADDR(sizeof(u32)))) {
1736                return;
1737        }
1738        /* Store load address of .dllview section */
1739        hndl->dm.dbthis = dllview_info.load_addr;
1740        /* Store memory context (segid) in which .dllview section
1741         * was  allocated */
1742        hndl->dm.context = dllview_info.context;
1743        mlist->refcount += 1;
1744        /* swap bytes in the entire debug record, but not the string table */
1745        if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
1746                swap_words(dbmod, (char *)dbsec - (char *)dbmod,
1747                           DLL_MODULE_BITMAP);
1748        }
1749        /* Update the DLLview list on the DSP write new record */
1750        if (!dlthis->myio->writemem(dlthis->myio, dbmod,
1751                                    dllview_info.load_addr, &dllview_info,
1752                                    TADDR_TO_HOST(dllview_info.size))) {
1753                return;
1754        }
1755        /* write new header */
1756        mhdr.first_module_size = hndl->dm.dbsiz;
1757        mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr);
1758        /* swap bytes in the module header, if needed */
1759        if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
1760                swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
1761                           MODULES_HEADER_BITMAP);
1762        }
1763        dllview_info = dllview_info_init;
1764        if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis,
1765                                    &dllview_info,
1766                                    sizeof(struct modules_header) -
1767                                    sizeof(u16))) {
1768                return;
1769        }
1770        /* Add the module handle to this processor's list
1771           of handles with debug info */
1772        hndl->dm.next = mlist->next;
1773        if (hndl->dm.next)
1774                hndl->dm.next->dm.prev = hndl;
1775        hndl->dm.prev = (struct my_handle *)mlist;
1776        mlist->next = hndl;     /* insert after root */
1777}                               /* init_module_handle */
1778
1779/*************************************************************************
1780 * Procedure dynamic_unload_module
1781 *
1782 * Parameters:
1783 *      mhandle A module handle from dynamic_load_module
1784 *      syms    Host-side symbol table and malloc/free functions
1785 *      alloc   Target-side memory allocation
1786 *
1787 * Effect:
1788 *      The module specified by mhandle is unloaded.  Unloading causes all
1789 * target memory to be deallocated, all symbols defined by the module to
1790 * be purged, and any host-side storage used by the dynamic loader for
1791 * this module to be released.
1792 *
1793 * Returns:
1794 *      Zero for success. On error, the number of errors detected is returned.
1795 * Individual errors are reported using syms->error_report().
1796 *********************************************************************** */
1797int dynamic_unload_module(void *mhandle,
1798                          struct dynamic_loader_sym *syms,
1799                          struct dynamic_loader_allocate *alloc,
1800                          struct dynamic_loader_initialize *init)
1801{
1802        s16 curr_sect;
1803        struct ldr_section_info *asecs;
1804        struct my_handle *hndl;
1805        struct dbg_mirror_root *root;
1806        unsigned errcount = 0;
1807        struct ldr_section_info dllview_info = dllview_info_init;
1808        struct modules_header mhdr;
1809
1810        hndl = (struct my_handle *)mhandle;
1811        if (!hndl)
1812                return 0;       /* if handle is null, nothing to do */
1813        /* Clear out the module symbols
1814         * Note that if this is the module that defined MODULES_HEADER
1815         (the head of the target debug list)
1816         * then this operation will blow away that symbol.
1817         It will therefore be impossible for subsequent
1818         * operations to add entries to this un-referenceable list. */
1819        if (!syms)
1820                return 1;
1821        syms->purge_symbol_table(syms, (unsigned)hndl);
1822        /* Deallocate target memory for sections
1823         * NOTE: The trampoline section, if created, gets deleted here, too */
1824
1825        asecs = hndl->secns;
1826        if (alloc)
1827                for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0;
1828                     curr_sect -= 1) {
1829                        asecs->name = NULL;
1830                        alloc->dload_deallocate(alloc, asecs++);
1831                }
1832        root = hndl->dm.root;
1833        if (!root) {
1834                /* there is a debug list containing this module */
1835                goto func_end;
1836        }
1837        if (!hndl->dm.dbthis) { /* target-side dllview record exists */
1838                goto loop_end;
1839        }
1840        /* Retrieve memory context in which .dllview was allocated */
1841        dllview_info.context = hndl->dm.context;
1842        if (hndl->dm.prev == hndl)
1843                goto exitunltgt;
1844
1845        /* target-side dllview record is in list */
1846        /* dequeue this record from our GPP-side mirror list */
1847        hndl->dm.prev->dm.next = hndl->dm.next;
1848        if (hndl->dm.next)
1849                hndl->dm.next->dm.prev = hndl->dm.prev;
1850        /* Update next_module of previous entry in target list
1851         * We are using mhdr here as a surrogate for either a
1852         struct modules_header or a dll_module */
1853        if (hndl->dm.next) {
1854                mhdr.first_module = TADDR_TO_TDATA(hndl->dm.next->dm.dbthis);
1855                mhdr.first_module_size = hndl->dm.next->dm.dbsiz;
1856        } else {
1857                mhdr.first_module = 0;
1858                mhdr.first_module_size = 0;
1859        }
1860        if (!init)
1861                goto exitunltgt;
1862
1863        if (!init->connect(init)) {
1864                dload_syms_error(syms, iconnect);
1865                errcount += 1;
1866                goto exitunltgt;
1867        }
1868        /* swap bytes in the module header, if needed */
1869        if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) {
1870                swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
1871                           MODULES_HEADER_BITMAP);
1872        }
1873        if (!init->writemem(init, &mhdr, hndl->dm.prev->dm.dbthis,
1874                            &dllview_info, sizeof(struct modules_header) -
1875                            sizeof(mhdr.update_flag))) {
1876                dload_syms_error(syms, dlvwrite);
1877                errcount += 1;
1878        }
1879        /* update change counter */
1880        root->changes += 1;
1881        if (!init->writemem(init, &(root->changes),
1882                            root->dbthis + HOST_TO_TADDR
1883                            (sizeof(mhdr.first_module) +
1884                             sizeof(mhdr.first_module_size)),
1885                            &dllview_info, sizeof(mhdr.update_flag))) {
1886                dload_syms_error(syms, dlvwrite);
1887                errcount += 1;
1888        }
1889        init->release(init);
1890exitunltgt:
1891        /* release target storage */
1892        dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
1893        dllview_info.load_addr = hndl->dm.dbthis;
1894        if (alloc)
1895                alloc->dload_deallocate(alloc, &dllview_info);
1896        root->refcount -= 1;
1897        /* target-side dllview record exists */
1898loop_end:
1899#ifndef DEBUG_HEADER_IN_LOADER
1900        if (root->refcount <= 0) {
1901                /* if all references gone, blow off the header */
1902                /* our root symbol may be gone due to the Purge above,
1903                   but if not, do not destroy the root */
1904                if (syms->find_matching_symbol
1905                    (syms, loader_dllview_root) == NULL)
1906                        syms->dload_deallocate(syms, root);
1907        }
1908#endif
1909func_end:
1910        /* there is a debug list containing this module */
1911        syms->dload_deallocate(syms, mhandle);  /* release our storage */
1912        return errcount;
1913}                               /* dynamic_unload_module */
1914
1915#if BITS_PER_AU > BITS_PER_BYTE
1916/*************************************************************************
1917 * Procedure unpack_name
1918 *
1919 * Parameters:
1920 *      soffset Byte offset into the string table
1921 *
1922 * Effect:
1923 *      Returns a pointer to the string specified by the offset supplied, or
1924 * NULL for error.
1925 *
1926 *********************************************************************** */
1927static char *unpack_name(struct dload_state *dlthis, u32 soffset)
1928{
1929        u8 tmp, *src;
1930        char *dst;
1931
1932        if (soffset >= dlthis->dfile_hdr.df_strtab_size) {
1933                dload_error(dlthis, "Bad string table offset " FMT_UI32,
1934                            soffset);
1935                return NULL;
1936        }
1937        src = (uint_least8_t *) dlthis->str_head +
1938            (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
1939        dst = dlthis->str_temp;
1940        if (soffset & 1)
1941                *dst++ = *src++;        /* only 1 character in first word */
1942        do {
1943                tmp = *src++;
1944                *dst = (tmp >> BITS_PER_BYTE);
1945                if (!(*dst++))
1946                        break;
1947        } while ((*dst++ = tmp & BYTE_MASK));
1948        dlthis->temp_len = dst - dlthis->str_temp;
1949        /* squirrel away length including terminating null */
1950        return dlthis->str_temp;
1951}                               /* unpack_name */
1952#endif
1953