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 *********************************************************************** */
dload_error(struct dload_state * dlthis,const char * errtxt,...)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 *********************************************************************** */
dload_syms_error(struct dynamic_loader_sym * syms,const char * errtxt,...)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 ********************************************************************** */
dynamic_load_module(struct dynamic_loader_stream * module,struct dynamic_loader_sym * syms,struct dynamic_loader_allocate * alloc,struct dynamic_loader_initialize * init,unsigned options,void ** mhandle)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
dynamic_open_module(struct dynamic_loader_stream * module,struct dynamic_loader_sym * syms,struct dynamic_loader_allocate * alloc,struct dynamic_loader_initialize * init,unsigned options,void ** mhandle)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
dload_headers(struct dload_state * dlthis)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 *********************************************************************** */
dload_sections(struct dload_state * dlthis)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 **************************************************************************** */
allocate_sections(struct dload_state * dlthis)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 *********************************************************************** */
section_table_free(struct dload_state * dlthis)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
dload_strings(struct dload_state * dlthis,bool sec_names_only)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 ************************************************************************ */
string_table_free(struct dload_state * dlthis)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
dload_symbols(struct dload_state * dlthis)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 **************************************************************************** */
symbol_table_free(struct dload_state * dlthis)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 *********************************************************************** */
cload_cinit(struct dload_state * dlthis,struct image_packet_t * ipacket)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 */
relocate_packet(struct dload_state * dlthis,struct image_packet_t * ipacket,u32 * checks,bool * tramps_generated)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 *********************************************************************** */
dload_data(struct dload_state * dlthis)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
dload_reorder(void * data,int dsiz,unsigned int map)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 *********************************************************************** */
dload_checksum(void * data,unsigned siz)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 ********************************************************************** */
dload_reverse_checksum(void * data,unsigned siz)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)
dload_reverse_checksum16(void * data,unsigned siz)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 *********************************************************************** */
swap_words(void * data,unsigned siz,unsigned bitmap)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 *********************************************************************** */
copy_tgt_strings(void * dstp,void * srcp,unsigned charcount)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
init_module_handle(struct dload_state * dlthis)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 *********************************************************************** */
dynamic_unload_module(void * mhandle,struct dynamic_loader_sym * syms,struct dynamic_loader_allocate * alloc,struct dynamic_loader_initialize * init)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 *********************************************************************** */
unpack_name(struct dload_state * dlthis,u32 soffset)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
1953