• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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