Linux-libre 3.12.18-gnu
[librecmc/linux-libre.git] / drivers / staging / tidspbridge / dynload / cload.c
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  */
27 static void dload_symbols(struct dload_state *dlthis);
28 static void dload_data(struct dload_state *dlthis);
29 static void allocate_sections(struct dload_state *dlthis);
30 static void string_table_free(struct dload_state *dlthis);
31 static void symbol_table_free(struct dload_state *dlthis);
32 static void section_table_free(struct dload_state *dlthis);
33 static void init_module_handle(struct dload_state *dlthis);
34 #if BITS_PER_AU > BITS_PER_BYTE
35 static char *unpack_name(struct dload_state *dlthis, u32 soffset);
36 #endif
37
38 static const char cinitname[] = { ".cinit" };
39 static const char loader_dllview_root[] = { "?DLModules?" };
40
41 /*
42  * Error strings
43  */
44 static const char readstrm[] = { "Error reading %s from input stream" };
45 static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
46 static const char tgtalloc[] = {
47         "Target memory allocate failed, section %s size " FMT_UI32 };
48 static const char initfail[] = { "%s to target address " FMT_UI32 " failed" };
49 static const char dlvwrite[] = { "Write to DLLview list failed" };
50 static const char iconnect[] = { "Connect call to init interface failed" };
51 static 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  *********************************************************************** */
63 void 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  *********************************************************************** */
86 void 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  ********************************************************************** */
120 int 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  ********************************************************************** */
228 int
229 dynamic_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
321 void 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
417 static 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  *********************************************************************** */
428 void 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  **************************************************************************** */
473 static 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  *********************************************************************** */
570 static 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  *********************************************************************** */
591 static const char stringtbl[] = { "string table" };
592
593 void 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  ************************************************************************ */
665 static 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
687 static 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
704 static 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                         }
870 loop_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 */
888 loop_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
898 free_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  **************************************************************************** */
915 static 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 */
940 static 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  *********************************************************************** */
954 static 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
1052 loopexit:
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 */
1080 static 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 */
1128 static const char imagepak[] = { "image packet" };
1129
1130 struct 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  *********************************************************************** */
1145 static 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);
1343 loop_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         }
1353 free_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
1375 void 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  *********************************************************************** */
1404 u32 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  ********************************************************************** */
1435 u32 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)
1456 u32 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  *********************************************************************** */
1489 static 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  *********************************************************************** */
1541 static 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
1581 static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1582         (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0
1583 };
1584 #else
1585 static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1586         (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0
1587 };
1588 #endif
1589 static 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  *********************************************************************** */
1797 int 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);
1890 exitunltgt:
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 */
1898 loop_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
1909 func_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  *********************************************************************** */
1927 static 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