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