Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cload.c
Go to the documentation of this file.
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  ********************************************************************** */
121  struct dynamic_loader_sym *syms,
122  struct dynamic_loader_allocate *alloc,
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
230  struct dynamic_loader_sym *syms,
231  struct dynamic_loader_allocate *alloc,
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,
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 */
342  map);
343  }
344  if (dlthis->dfile_hdr.df_byte_reshuffle !=
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 !=
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) +
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,
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;
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 =
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 !=
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,
1583 };
1584 #else
1585 static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 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,
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 */
1746  swap_words(dbmod, (char *)dbsec - (char *)dbmod,
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 */
1760  swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
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,
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),
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