• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/tidspbridge/dynload/
1/*
2 * tramp.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Copyright (C) 2009 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#if TMS32060
20#include "tramp_table_c6000.c"
21#endif
22
23#define MAX_RELOS_PER_PASS	4
24
25/*
26 * Function:	priv_tramp_sect_tgt_alloc
27 * Description: Allocate target memory for the trampoline section.  The
28 *	  target mem size is easily obtained as the next available address.
29 */
30static int priv_tramp_sect_tgt_alloc(struct dload_state *dlthis)
31{
32	int ret_val = 0;
33	struct ldr_section_info *sect_info;
34
35	/*  Populate the trampoline loader section and allocate it on the
36	 * target.  The section name is ALWAYS the first string in the final
37	 * string table for trampolines.  The trampoline section is always
38	 * 1 beyond the total number of allocated sections. */
39	sect_info = &dlthis->ldr_sections[dlthis->allocated_secn_count];
40
41	sect_info->name = dlthis->tramp.final_string_table;
42	sect_info->size = dlthis->tramp.tramp_sect_next_addr;
43	sect_info->context = 0;
44	sect_info->type =
45	    (4 << 8) | DLOAD_TEXT | DS_ALLOCATE_MASK | DS_DOWNLOAD_MASK;
46	sect_info->page = 0;
47	sect_info->run_addr = 0;
48	sect_info->load_addr = 0;
49	ret_val = dlthis->myalloc->dload_allocate(dlthis->myalloc,
50						  sect_info,
51						  ds_alignment
52						  (sect_info->type));
53
54	if (ret_val == 0)
55		dload_error(dlthis, "Failed to allocate target memory for"
56			    " trampoline");
57
58	return ret_val;
59}
60
61/*
62 * Function:	priv_h2a
63 * Description: Helper function to convert a hex value to its ASCII
64 *	  representation.  Used for trampoline symbol name generation.
65 */
66static u8 priv_h2a(u8 value)
67{
68	if (value > 0xF)
69		return 0xFF;
70
71	if (value <= 9)
72		value += 0x30;
73	else
74		value += 0x37;
75
76	return value;
77}
78
79/*
80 * Function:	priv_tramp_sym_gen_name
81 * Description: Generate a trampoline symbol name (ASCII) using the value
82 *	  of the symbol.  This places the new name into the user buffer.
83 *	  The name is fixed in length and of the form: __$dbTR__xxxxxxxx
84 *	  (where "xxxxxxxx" is the hex value.
85 */
86static void priv_tramp_sym_gen_name(u32 value, char *dst)
87{
88	u32 i;
89	char *prefix = TRAMP_SYM_PREFIX;
90	char *dst_local = dst;
91	u8 tmp;
92
93	/*  Clear out the destination, including the ending NULL */
94	for (i = 0; i < (TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN); i++)
95		*(dst_local + i) = 0;
96
97	/*  Copy the prefix to start */
98	for (i = 0; i < strlen(TRAMP_SYM_PREFIX); i++) {
99		*dst_local = *(prefix + i);
100		dst_local++;
101	}
102
103	/*  Now convert the value passed in to a string equiv of the hex */
104	for (i = 0; i < sizeof(value); i++) {
105#ifndef _BIG_ENDIAN
106		tmp = *(((u8 *) &value) + (sizeof(value) - 1) - i);
107		*dst_local = priv_h2a((tmp & 0xF0) >> 4);
108		dst_local++;
109		*dst_local = priv_h2a(tmp & 0x0F);
110		dst_local++;
111#else
112		tmp = *(((u8 *) &value) + i);
113		*dst_local = priv_h2a((tmp & 0xF0) >> 4);
114		dst_local++;
115		*dst_local = priv_h2a(tmp & 0x0F);
116		dst_local++;
117#endif
118	}
119
120	/*  NULL terminate */
121	*dst_local = 0;
122}
123
124/*
125 * Function:	priv_tramp_string_create
126 * Description: Create a new string specific to the trampoline loading and add
127 *	  it to the trampoline string list.  This list contains the
128 *	  trampoline section name and trampoline point symbols.
129 */
130static struct tramp_string *priv_tramp_string_create(struct dload_state *dlthis,
131						     u32 str_len, char *str)
132{
133	struct tramp_string *new_string = NULL;
134	u32 i;
135
136	/*  Create a new string object with the specified size. */
137	new_string =
138	    (struct tramp_string *)dlthis->mysym->dload_allocate(dlthis->mysym,
139								 (sizeof
140								  (struct
141								   tramp_string)
142								  + str_len +
143								  1));
144	if (new_string != NULL) {
145		/*  Clear the string first.  This ensures the ending NULL is
146		 * present and the optimizer won't touch it. */
147		for (i = 0; i < (sizeof(struct tramp_string) + str_len + 1);
148		     i++)
149			*((u8 *) new_string + i) = 0;
150
151		/*  Add this string to our virtual table by assigning it the
152		 * next index and pushing it to the tail of the list. */
153		new_string->index = dlthis->tramp.tramp_string_next_index;
154		dlthis->tramp.tramp_string_next_index++;
155		dlthis->tramp.tramp_string_size += str_len + 1;
156
157		new_string->next = NULL;
158		if (dlthis->tramp.string_head == NULL)
159			dlthis->tramp.string_head = new_string;
160		else
161			dlthis->tramp.string_tail->next = new_string;
162
163		dlthis->tramp.string_tail = new_string;
164
165		/*  Copy the string over to the new object */
166		for (i = 0; i < str_len; i++)
167			new_string->str[i] = str[i];
168	}
169
170	return new_string;
171}
172
173/*
174 * Function:	priv_tramp_string_find
175 * Description: Walk the trampoline string list and find a match for the
176 *	  provided string.  If not match is found, NULL is returned.
177 */
178static struct tramp_string *priv_tramp_string_find(struct dload_state *dlthis,
179						   char *str)
180{
181	struct tramp_string *cur_str = NULL;
182	struct tramp_string *ret_val = NULL;
183	u32 i;
184	u32 str_len = strlen(str);
185
186	for (cur_str = dlthis->tramp.string_head;
187	     (ret_val == NULL) && (cur_str != NULL); cur_str = cur_str->next) {
188		/*  If the string lengths aren't equal, don't bother
189		 * comparing */
190		if (str_len != strlen(cur_str->str))
191			continue;
192
193		/*  Walk the strings until one of them ends */
194		for (i = 0; i < str_len; i++) {
195			/*  If they don't match in the current position then
196			 * break out now, no sense in continuing to look at
197			 * this string. */
198			if (str[i] != cur_str->str[i])
199				break;
200		}
201
202		if (i == str_len)
203			ret_val = cur_str;
204	}
205
206	return ret_val;
207}
208
209/*
210 * Function:	priv_string_tbl_finalize
211 * Description: Flatten the trampoline string list into a table of NULL
212 *	  terminated strings.  This is the same format of string table
213 *	  as used by the COFF/DOFF file.
214 */
215static int priv_string_tbl_finalize(struct dload_state *dlthis)
216{
217	int ret_val = 0;
218	struct tramp_string *cur_string;
219	char *cur_loc;
220	char *tmp;
221
222	/*  Allocate enough space for all strings that have been created.  The
223	 * table is simply all strings concatenated together will NULL
224	 * endings. */
225	dlthis->tramp.final_string_table =
226	    (char *)dlthis->mysym->dload_allocate(dlthis->mysym,
227						  dlthis->tramp.
228						  tramp_string_size);
229	if (dlthis->tramp.final_string_table != NULL) {
230		/*  We got our buffer, walk the list and release the nodes as*
231		 * we go */
232		cur_loc = dlthis->tramp.final_string_table;
233		cur_string = dlthis->tramp.string_head;
234		while (cur_string != NULL) {
235			/*  Move the head/tail pointers */
236			dlthis->tramp.string_head = cur_string->next;
237			if (dlthis->tramp.string_tail == cur_string)
238				dlthis->tramp.string_tail = NULL;
239
240			/*  Copy the string contents */
241			for (tmp = cur_string->str;
242			     *tmp != '\0'; tmp++, cur_loc++)
243				*cur_loc = *tmp;
244
245			/*  Pick up the NULL termination since it was missed by
246			 * breaking using it to end the above loop. */
247			*cur_loc = '\0';
248			cur_loc++;
249
250			/*  Free the string node, we don't need it any more. */
251			dlthis->mysym->dload_deallocate(dlthis->mysym,
252							cur_string);
253
254			/*  Move our pointer to the next one */
255			cur_string = dlthis->tramp.string_head;
256		}
257
258		/*  Update our return value to success */
259		ret_val = 1;
260	} else
261		dload_error(dlthis, "Failed to allocate trampoline "
262			    "string table");
263
264	return ret_val;
265}
266
267/*
268 * Function:	priv_tramp_sect_alloc
269 * Description: Virtually allocate space from the trampoline section.  This
270 *	  function returns the next offset within the trampoline section
271 *	  that is available and moved the next available offset by the
272 *	  requested size.  NO TARGET ALLOCATION IS DONE AT THIS TIME.
273 */
274static u32 priv_tramp_sect_alloc(struct dload_state *dlthis, u32 tramp_size)
275{
276	u32 ret_val;
277
278	/*  If the next available address is 0, this is our first allocation.
279	 * Create a section name string to go into the string table . */
280	if (dlthis->tramp.tramp_sect_next_addr == 0) {
281		dload_syms_error(dlthis->mysym, "*** WARNING ***  created "
282				 "dynamic TRAMPOLINE section for module %s",
283				 dlthis->str_head);
284	}
285
286	/*  Reserve space for the new trampoline */
287	ret_val = dlthis->tramp.tramp_sect_next_addr;
288	dlthis->tramp.tramp_sect_next_addr += tramp_size;
289	return ret_val;
290}
291
292/*
293 * Function:	priv_tramp_sym_create
294 * Description: Allocate and create a new trampoline specific symbol and add
295 *	  it to the trampoline symbol list.  These symbols will include
296 *	  trampoline points as well as the external symbols they
297 *	  reference.
298 */
299static struct tramp_sym *priv_tramp_sym_create(struct dload_state *dlthis,
300					       u32 str_index,
301					       struct local_symbol *tmp_sym)
302{
303	struct tramp_sym *new_sym = NULL;
304	u32 i;
305
306	/*  Allocate new space for the symbol in the symbol table. */
307	new_sym =
308	    (struct tramp_sym *)dlthis->mysym->dload_allocate(dlthis->mysym,
309					      sizeof(struct tramp_sym));
310	if (new_sym != NULL) {
311		for (i = 0; i != sizeof(struct tramp_sym); i++)
312			*((char *)new_sym + i) = 0;
313
314		/*  Assign this symbol the next symbol index for easier
315		 * reference later during relocation. */
316		new_sym->index = dlthis->tramp.tramp_sym_next_index;
317		dlthis->tramp.tramp_sym_next_index++;
318
319		/*  Populate the symbol information.  At this point any
320		 * trampoline symbols will be the offset location, not the
321		 * final.  Copy over the symbol info to start, then be sure to
322		 * get the string index from the trampoline string table. */
323		new_sym->sym_info = *tmp_sym;
324		new_sym->str_index = str_index;
325
326		/*  Push the new symbol to the tail of the symbol table list */
327		new_sym->next = NULL;
328		if (dlthis->tramp.symbol_head == NULL)
329			dlthis->tramp.symbol_head = new_sym;
330		else
331			dlthis->tramp.symbol_tail->next = new_sym;
332
333		dlthis->tramp.symbol_tail = new_sym;
334	}
335
336	return new_sym;
337}
338
339/*
340 * Function:	priv_tramp_sym_get
341 * Description: Search for the symbol with the matching string index (from
342 *	  the trampoline string table) and return the trampoline
343 *	  symbol object, if found.  Otherwise return NULL.
344 */
345static struct tramp_sym *priv_tramp_sym_get(struct dload_state *dlthis,
346					    u32 string_index)
347{
348	struct tramp_sym *sym_found = NULL;
349
350	/*  Walk the symbol table list and search vs. the string index */
351	for (sym_found = dlthis->tramp.symbol_head;
352	     sym_found != NULL; sym_found = sym_found->next) {
353		if (sym_found->str_index == string_index)
354			break;
355	}
356
357	return sym_found;
358}
359
360/*
361 * Function:	priv_tramp_sym_find
362 * Description: Search for a trampoline symbol based on the string name of
363 *	  the symbol.  Return the symbol object, if found, otherwise
364 *	  return NULL.
365 */
366static struct tramp_sym *priv_tramp_sym_find(struct dload_state *dlthis,
367					     char *string)
368{
369	struct tramp_sym *sym_found = NULL;
370	struct tramp_string *str_found = NULL;
371
372	/*  First, search for the string, then search for the sym based on the
373	   string index. */
374	str_found = priv_tramp_string_find(dlthis, string);
375	if (str_found != NULL)
376		sym_found = priv_tramp_sym_get(dlthis, str_found->index);
377
378	return sym_found;
379}
380
381/*
382 * Function:	priv_tramp_sym_finalize
383 * Description: Allocate a flat symbol table for the trampoline section,
384 *	  put each trampoline symbol into the table, adjust the
385 *	  symbol value based on the section address on the target and
386 *	  free the trampoline symbol list nodes.
387 */
388static int priv_tramp_sym_finalize(struct dload_state *dlthis)
389{
390	int ret_val = 0;
391	struct tramp_sym *cur_sym;
392	struct ldr_section_info *tramp_sect =
393	    &dlthis->ldr_sections[dlthis->allocated_secn_count];
394	struct local_symbol *new_sym;
395
396	/*  Allocate a table to hold a flattened version of all symbols
397	 * created. */
398	dlthis->tramp.final_sym_table =
399	    (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
400				 (sizeof(struct local_symbol) * dlthis->tramp.
401						  tramp_sym_next_index));
402	if (dlthis->tramp.final_sym_table != NULL) {
403		/*  Walk the list of all symbols, copy it over to the flattened
404		 * table. After it has been copied, the node can be freed as
405		 * it is no longer needed. */
406		new_sym = dlthis->tramp.final_sym_table;
407		cur_sym = dlthis->tramp.symbol_head;
408		while (cur_sym != NULL) {
409			/*  Pop it off the list */
410			dlthis->tramp.symbol_head = cur_sym->next;
411			if (cur_sym == dlthis->tramp.symbol_tail)
412				dlthis->tramp.symbol_tail = NULL;
413
414			/*  Copy the symbol contents into the flat table */
415			*new_sym = cur_sym->sym_info;
416
417			/*  Now finaize the symbol.  If it is in the tramp
418			 * section, we need to adjust for the section start.
419			 * If it is external then we don't need to adjust at
420			 * all.
421			 * NOTE: THIS CODE ASSUMES THAT THE TRAMPOLINE IS
422			 * REFERENCED LIKE A CALL TO AN EXTERNAL SO VALUE AND
423			 * DELTA ARE THE SAME.  SEE THE FUNCTION dload_symbols
424			 * WHERE DN_UNDEF IS HANDLED FOR MORE REFERENCE. */
425			if (new_sym->secnn < 0) {
426				new_sym->value += tramp_sect->load_addr;
427				new_sym->delta = new_sym->value;
428			}
429
430			/*  Let go of the symbol node */
431			dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
432
433			/*  Move to the next node */
434			cur_sym = dlthis->tramp.symbol_head;
435			new_sym++;
436		}
437
438		ret_val = 1;
439	} else
440		dload_error(dlthis, "Failed to alloc trampoline sym table");
441
442	return ret_val;
443}
444
445/*
446 * Function:	priv_tgt_img_gen
447 * Description: Allocate storage for and copy the target specific image data
448 *	and fix up its relocations for the new external symbol.  If
449 *	a trampoline image packet was successfully created it is added
450 *	to the trampoline list.
451 */
452static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base,
453			    u32 gen_index, struct tramp_sym *new_ext_sym)
454{
455	struct tramp_img_pkt *new_img_pkt = NULL;
456	u32 i;
457	u32 pkt_size = tramp_img_pkt_size_get();
458	u8 *gen_tbl_entry;
459	u8 *pkt_data;
460	struct reloc_record_t *cur_relo;
461	int ret_val = 0;
462
463	/*  Allocate a new image packet and set it up. */
464	new_img_pkt =
465	    (struct tramp_img_pkt *)dlthis->mysym->dload_allocate(dlthis->mysym,
466								  pkt_size);
467	if (new_img_pkt != NULL) {
468		/*  Save the base, this is where it goes in the section */
469		new_img_pkt->base = base;
470
471		/*  Copy over the image data and relos from the target table */
472		pkt_data = (u8 *) &new_img_pkt->hdr;
473		gen_tbl_entry = (u8 *) &tramp_gen_info[gen_index];
474		for (i = 0; i < pkt_size; i++) {
475			*pkt_data = *gen_tbl_entry;
476			pkt_data++;
477			gen_tbl_entry++;
478		}
479
480		/*  Update the relocations to point to the external symbol */
481		cur_relo =
482		    (struct reloc_record_t *)((u8 *) &new_img_pkt->hdr +
483					      new_img_pkt->hdr.relo_offset);
484		for (i = 0; i < new_img_pkt->hdr.num_relos; i++)
485			cur_relo[i].SYMNDX = new_ext_sym->index;
486
487		/*  Add it to the trampoline list. */
488		new_img_pkt->next = dlthis->tramp.tramp_pkts;
489		dlthis->tramp.tramp_pkts = new_img_pkt;
490
491		ret_val = 1;
492	}
493
494	return ret_val;
495}
496
497/*
498 * Function:	priv_pkt_relo
499 * Description: Take the provided image data and the collection of relocations
500 *	  for it and perform the relocations.  Note that all relocations
501 *	  at this stage are considered SECOND PASS since the original
502 *	  image has already been processed in the first pass.  This means
503 *	  TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really
504 *	  the first (and only) relocation that will be performed on them.
505 */
506static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data,
507			 struct reloc_record_t *rp[], u32 relo_count)
508{
509	int ret_val = 1;
510	u32 i;
511	bool tmp;
512
513	/*  Walk through all of the relos and process them.  This function is
514	 * the equivalent of relocate_packet() from cload.c, but specialized
515	 * for trampolines and 2nd phase relocations. */
516	for (i = 0; i < relo_count; i++)
517		dload_relocate(dlthis, data, rp[i], &tmp, true);
518
519	return ret_val;
520}
521
522/*
523 * Function:	priv_tramp_pkt_finalize
524 * Description: Walk the list of all trampoline packets and finalize them.
525 *	  Each trampoline image packet will be relocated now that the
526 *	  trampoline section has been allocated on the target.  Once
527 *	  all of the relocations are done the trampoline image data
528 *	  is written into target memory and the trampoline packet
529 *	  is freed: it is no longer needed after this point.
530 */
531static int priv_tramp_pkt_finalize(struct dload_state *dlthis)
532{
533	int ret_val = 1;
534	struct tramp_img_pkt *cur_pkt = NULL;
535	struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
536	u32 relos_done;
537	u32 i;
538	struct reloc_record_t *cur_relo;
539	struct ldr_section_info *sect_info =
540	    &dlthis->ldr_sections[dlthis->allocated_secn_count];
541
542	/*  Walk the list of trampoline packets and relocate each packet.  This
543	 * function is the trampoline equivalent of dload_data() from
544	 * cload.c. */
545	cur_pkt = dlthis->tramp.tramp_pkts;
546	while ((ret_val != 0) && (cur_pkt != NULL)) {
547		/*  Remove the pkt from the list */
548		dlthis->tramp.tramp_pkts = cur_pkt->next;
549
550		/*  Setup section and image offset information for the relo */
551		dlthis->image_secn = sect_info;
552		dlthis->image_offset = cur_pkt->base;
553		dlthis->delta_runaddr = sect_info->run_addr;
554
555		/*  Walk through all relos for the packet */
556		relos_done = 0;
557		cur_relo = (struct reloc_record_t *)((u8 *) &cur_pkt->hdr +
558						     cur_pkt->hdr.relo_offset);
559		while (relos_done < cur_pkt->hdr.num_relos) {
560#ifdef ENABLE_TRAMP_DEBUG
561			dload_syms_error(dlthis->mysym,
562					 "===> Trampoline %x branches to %x",
563					 sect_info->run_addr +
564					 dlthis->image_offset,
565					 dlthis->
566					 tramp.final_sym_table[cur_relo->
567							       SYMNDX].value);
568#endif
569
570			for (i = 0;
571			     ((i < MAX_RELOS_PER_PASS) &&
572			      ((i + relos_done) < cur_pkt->hdr.num_relos)); i++)
573				relos[i] = cur_relo + i;
574
575			/*  Do the actual relo */
576			ret_val = priv_pkt_relo(dlthis,
577						(tgt_au_t *) &cur_pkt->payload,
578						relos, i);
579			if (ret_val == 0) {
580				dload_error(dlthis,
581					    "Relocation of trampoline pkt at %x"
582					    " failed", cur_pkt->base +
583					    sect_info->run_addr);
584				break;
585			}
586
587			relos_done += i;
588			cur_relo += i;
589		}
590
591		/*  Make sure we didn't hit a problem */
592		if (ret_val != 0) {
593			/*  Relos are done for the packet, write it to the
594			 * target */
595			ret_val = dlthis->myio->writemem(dlthis->myio,
596							 &cur_pkt->payload,
597							 sect_info->load_addr +
598							 cur_pkt->base,
599							 sect_info,
600							 BYTE_TO_HOST
601							 (cur_pkt->hdr.
602							  tramp_code_size));
603			if (ret_val == 0) {
604				dload_error(dlthis,
605					    "Write to " FMT_UI32 " failed",
606					    sect_info->load_addr +
607					    cur_pkt->base);
608			}
609
610			/*  Done with the pkt, let it go */
611			dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
612
613			/*  Get the next packet to process */
614			cur_pkt = dlthis->tramp.tramp_pkts;
615		}
616	}
617
618	return ret_val;
619}
620
621/*
622 * Function:	priv_dup_pkt_finalize
623 * Description: Walk the list of duplicate image packets and finalize them.
624 *	  Each duplicate packet will be relocated again for the
625 *	  relocations that previously failed and have been adjusted
626 *	  to point at a trampoline.  Once all relocations for a packet
627 *	  have been done, write the packet into target memory.  The
628 *	  duplicate packet and its relocation chain are all freed
629 *	  after use here as they are no longer needed after this.
630 */
631static int priv_dup_pkt_finalize(struct dload_state *dlthis)
632{
633	int ret_val = 1;
634	struct tramp_img_dup_pkt *cur_pkt;
635	struct tramp_img_dup_relo *cur_relo;
636	struct reloc_record_t *relos[MAX_RELOS_PER_PASS];
637	struct doff_scnhdr_t *sect_hdr = NULL;
638	s32 i;
639
640	/* Similar to the trampoline pkt finalize, this function walks each dup
641	 * pkt that was generated and performs all relocations that were
642	 * deferred to a 2nd pass.  This is the equivalent of dload_data() from
643	 * cload.c, but does not need the additional reorder and checksum
644	 * processing as it has already been done. */
645	cur_pkt = dlthis->tramp.dup_pkts;
646	while ((ret_val != 0) && (cur_pkt != NULL)) {
647		/*  Remove the node from the list, we'll be freeing it
648		 * shortly */
649		dlthis->tramp.dup_pkts = cur_pkt->next;
650
651		/*  Setup the section and image offset for relocation */
652		dlthis->image_secn = &dlthis->ldr_sections[cur_pkt->secnn];
653		dlthis->image_offset = cur_pkt->offset;
654
655		/*  In order to get the delta run address, we need to reference
656		 * the original section header.  It's a bit ugly, but needed
657		 * for relo. */
658		i = (s32) (dlthis->image_secn - dlthis->ldr_sections);
659		sect_hdr = dlthis->sect_hdrs + i;
660		dlthis->delta_runaddr = sect_hdr->ds_paddr;
661
662		/*  Walk all relos in the chain and process each. */
663		cur_relo = cur_pkt->relo_chain;
664		while (cur_relo != NULL) {
665			/*  Process them a chunk at a time to be efficient */
666			for (i = 0; (i < MAX_RELOS_PER_PASS)
667			     && (cur_relo != NULL);
668			     i++, cur_relo = cur_relo->next) {
669				relos[i] = &cur_relo->relo;
670				cur_pkt->relo_chain = cur_relo->next;
671			}
672
673			/*  Do the actual relo */
674			ret_val = priv_pkt_relo(dlthis,
675						cur_pkt->img_pkt.img_data,
676						relos, i);
677			if (ret_val == 0) {
678				dload_error(dlthis,
679					    "Relocation of dup pkt at %x"
680					    " failed", cur_pkt->offset +
681					    dlthis->image_secn->run_addr);
682				break;
683			}
684
685			/*  Release all of these relos, we're done with them */
686			while (i > 0) {
687				dlthis->mysym->dload_deallocate(dlthis->mysym,
688						GET_CONTAINER
689						(relos[i - 1],
690						 struct tramp_img_dup_relo,
691						 relo));
692				i--;
693			}
694
695			/*  DO NOT ADVANCE cur_relo, IT IS ALREADY READY TO
696			 * GO! */
697		}
698
699		/* Done with all relos.  Make sure we didn't have a problem and
700		 * write it out to the target */
701		if (ret_val != 0) {
702			ret_val = dlthis->myio->writemem(dlthis->myio,
703							 cur_pkt->img_pkt.
704							 img_data,
705							 dlthis->image_secn->
706							 load_addr +
707							 cur_pkt->offset,
708							 dlthis->image_secn,
709							 BYTE_TO_HOST
710							 (cur_pkt->img_pkt.
711							  packet_size));
712			if (ret_val == 0) {
713				dload_error(dlthis,
714					    "Write to " FMT_UI32 " failed",
715					    dlthis->image_secn->load_addr +
716					    cur_pkt->offset);
717			}
718
719			dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
720
721			/*  Advance to the next packet */
722			cur_pkt = dlthis->tramp.dup_pkts;
723		}
724	}
725
726	return ret_val;
727}
728
729/*
730 * Function:	priv_dup_find
731 * Description: Walk the list of existing duplicate packets and find a
732 *	  match based on the section number and image offset.  Return
733 *	  the duplicate packet if found, otherwise NULL.
734 */
735static struct tramp_img_dup_pkt *priv_dup_find(struct dload_state *dlthis,
736					       s16 secnn, u32 image_offset)
737{
738	struct tramp_img_dup_pkt *cur_pkt = NULL;
739
740	for (cur_pkt = dlthis->tramp.dup_pkts;
741	     cur_pkt != NULL; cur_pkt = cur_pkt->next) {
742		if ((cur_pkt->secnn == secnn) &&
743		    (cur_pkt->offset == image_offset)) {
744			/*  Found a match, break out */
745			break;
746		}
747	}
748
749	return cur_pkt;
750}
751
752/*
753 * Function:	priv_img_pkt_dup
754 * Description: Duplicate the original image packet.  If this is the first
755 *	  time this image packet has been seen (based on section number
756 *	  and image offset), create a new duplicate packet and add it
757 *	  to the dup packet list.  If not, just get the existing one and
758 *	  update it with the current packet contents (since relocation
759 *	  on the packet is still ongoing in first pass.)  Create a
760 *	  duplicate of the provided relocation, but update it to point
761 *	  to the new trampoline symbol.  Add the new relocation dup to
762 *	  the dup packet's relo chain for 2nd pass relocation later.
763 */
764static int priv_img_pkt_dup(struct dload_state *dlthis,
765			    s16 secnn, u32 image_offset,
766			    struct image_packet_t *ipacket,
767			    struct reloc_record_t *rp,
768			    struct tramp_sym *new_tramp_sym)
769{
770	struct tramp_img_dup_pkt *dup_pkt = NULL;
771	u32 new_dup_size;
772	s32 i;
773	int ret_val = 0;
774	struct tramp_img_dup_relo *dup_relo = NULL;
775
776	/*  Determinne if this image packet is already being tracked in the
777	   dup list for other trampolines. */
778	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
779
780	if (dup_pkt == NULL) {
781		/*  This image packet does not exist in our tracking, so create
782		 * a new one and add it to the head of the list. */
783		new_dup_size = sizeof(struct tramp_img_dup_pkt) +
784		    ipacket->packet_size;
785
786		dup_pkt = (struct tramp_img_dup_pkt *)
787		    dlthis->mysym->dload_allocate(dlthis->mysym, new_dup_size);
788		if (dup_pkt != NULL) {
789			/*  Save off the section and offset information */
790			dup_pkt->secnn = secnn;
791			dup_pkt->offset = image_offset;
792			dup_pkt->relo_chain = NULL;
793
794			/*  Copy the original packet content */
795			dup_pkt->img_pkt = *ipacket;
796			dup_pkt->img_pkt.img_data = (u8 *) (dup_pkt + 1);
797			for (i = 0; i < ipacket->packet_size; i++)
798				*(dup_pkt->img_pkt.img_data + i) =
799				    *(ipacket->img_data + i);
800
801			/*  Add the packet to the dup list */
802			dup_pkt->next = dlthis->tramp.dup_pkts;
803			dlthis->tramp.dup_pkts = dup_pkt;
804		} else
805			dload_error(dlthis, "Failed to create dup packet!");
806	} else {
807		/*  The image packet contents could have changed since
808		 * trampoline detection happens during relocation of the image
809		 * packets.  So, we need to update the image packet contents
810		 * before adding relo information. */
811		for (i = 0; i < dup_pkt->img_pkt.packet_size; i++)
812			*(dup_pkt->img_pkt.img_data + i) =
813			    *(ipacket->img_data + i);
814	}
815
816	/*  Since the previous code may have allocated a new dup packet for us,
817	   double check that we actually have one. */
818	if (dup_pkt != NULL) {
819		/*  Allocate a new node for the relo chain.  Each image packet
820		 * can potentially have multiple relocations that cause a
821		 * trampoline to be generated.  So, we keep them in a chain,
822		 * order is not important. */
823		dup_relo = dlthis->mysym->dload_allocate(dlthis->mysym,
824					 sizeof(struct tramp_img_dup_relo));
825		if (dup_relo != NULL) {
826			/*  Copy the relo contents, adjust for the new
827			 * trampoline and add it to the list. */
828			dup_relo->relo = *rp;
829			dup_relo->relo.SYMNDX = new_tramp_sym->index;
830
831			dup_relo->next = dup_pkt->relo_chain;
832			dup_pkt->relo_chain = dup_relo;
833
834			/*  That's it, we're done.  Make sure we update our
835			 * return value to be success since everything finished
836			 * ok */
837			ret_val = 1;
838		} else
839			dload_error(dlthis, "Unable to alloc dup relo");
840	}
841
842	return ret_val;
843}
844
845/*
846 * Function:	dload_tramp_avail
847 * Description: Check to see if the target supports a trampoline for this type
848 *	  of relocation.  Return true if it does, otherwise false.
849 */
850bool dload_tramp_avail(struct dload_state *dlthis, struct reloc_record_t *rp)
851{
852	bool ret_val = false;
853	u16 map_index;
854	u16 gen_index;
855
856	/*  Check type hash vs. target tramp table */
857	map_index = HASH_FUNC(rp->TYPE);
858	gen_index = tramp_map[map_index];
859	if (gen_index != TRAMP_NO_GEN_AVAIL)
860		ret_val = true;
861
862	return ret_val;
863}
864
865/*
866 * Function:	dload_tramp_generate
867 * Description: Create a new trampoline for the provided image packet and
868 *	  relocation causing problems.  This will create the trampoline
869 *	  as well as duplicate/update the image packet and relocation
870 *	  causing the problem, which will be relo'd again during
871 *	  finalization.
872 */
873int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
874			 u32 image_offset, struct image_packet_t *ipacket,
875			 struct reloc_record_t *rp)
876{
877	u16 map_index;
878	u16 gen_index;
879	int ret_val = 1;
880	char tramp_sym_str[TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN];
881	struct local_symbol *ref_sym;
882	struct tramp_sym *new_tramp_sym;
883	struct tramp_sym *new_ext_sym;
884	struct tramp_string *new_tramp_str;
885	u32 new_tramp_base;
886	struct local_symbol tmp_sym;
887	struct local_symbol ext_tmp_sym;
888
889	/*  Hash the relo type to get our generator information */
890	map_index = HASH_FUNC(rp->TYPE);
891	gen_index = tramp_map[map_index];
892	if (gen_index != TRAMP_NO_GEN_AVAIL) {
893		/*  If this is the first trampoline, create the section name in
894		 * our string table for debug help later. */
895		if (dlthis->tramp.string_head == NULL) {
896			priv_tramp_string_create(dlthis,
897						 strlen(TRAMP_SECT_NAME),
898						 TRAMP_SECT_NAME);
899		}
900#ifdef ENABLE_TRAMP_DEBUG
901		dload_syms_error(dlthis->mysym,
902				 "Trampoline at img loc %x, references %x",
903				 dlthis->ldr_sections[secnn].run_addr +
904				 image_offset + rp->vaddr,
905				 dlthis->local_symtab[rp->SYMNDX].value);
906#endif
907
908		/*  Generate the trampoline string, check if already defined.
909		 * If the relo symbol index is -1, it means we need the section
910		 * info for relo later.  To do this we'll dummy up a symbol
911		 * with the section delta and run addresses. */
912		if (rp->SYMNDX == -1) {
913			ext_tmp_sym.value =
914			    dlthis->ldr_sections[secnn].run_addr;
915			ext_tmp_sym.delta = dlthis->sect_hdrs[secnn].ds_paddr;
916			ref_sym = &ext_tmp_sym;
917		} else
918			ref_sym = &(dlthis->local_symtab[rp->SYMNDX]);
919
920		priv_tramp_sym_gen_name(ref_sym->value, tramp_sym_str);
921		new_tramp_sym = priv_tramp_sym_find(dlthis, tramp_sym_str);
922		if (new_tramp_sym == NULL) {
923			/*  If tramp string not defined, create it and a new
924			 * string, and symbol for it as well as the original
925			 * symbol which caused the trampoline. */
926			new_tramp_str = priv_tramp_string_create(dlthis,
927								strlen
928								(tramp_sym_str),
929								 tramp_sym_str);
930			if (new_tramp_str == NULL) {
931				dload_error(dlthis, "Failed to create new "
932					    "trampoline string\n");
933				ret_val = 0;
934			} else {
935				/*  Allocate tramp section space for the new
936				 * tramp from the target */
937				new_tramp_base = priv_tramp_sect_alloc(dlthis,
938						       tramp_size_get());
939
940				/*  We have a string, create the new symbol and
941				 * duplicate the external. */
942				tmp_sym.value = new_tramp_base;
943				tmp_sym.delta = 0;
944				tmp_sym.secnn = -1;
945				tmp_sym.sclass = 0;
946				new_tramp_sym = priv_tramp_sym_create(dlthis,
947							      new_tramp_str->
948							      index,
949							      &tmp_sym);
950
951				new_ext_sym = priv_tramp_sym_create(dlthis, -1,
952								    ref_sym);
953
954				if ((new_tramp_sym != NULL) &&
955				    (new_ext_sym != NULL)) {
956					/*  Call the image generator to get the
957					 * new image data and fix up its
958					 * relocations for the external
959					 * symbol. */
960					ret_val = priv_tgt_img_gen(dlthis,
961								 new_tramp_base,
962								 gen_index,
963								 new_ext_sym);
964
965					/*  Add generated image data to tramp
966					 * image list */
967					if (ret_val != 1) {
968						dload_error(dlthis, "Failed to "
969							    "create img pkt for"
970							    " trampoline\n");
971					}
972				} else {
973					dload_error(dlthis, "Failed to create "
974						    "new tramp syms "
975						    "(%8.8X, %8.8X)\n",
976						    new_tramp_sym, new_ext_sym);
977					ret_val = 0;
978				}
979			}
980		}
981
982		/*  Duplicate the image data and relo record that caused the
983		 * tramp, including update the relo data to point to the tramp
984		 * symbol. */
985		if (ret_val == 1) {
986			ret_val = priv_img_pkt_dup(dlthis, secnn, image_offset,
987						   ipacket, rp, new_tramp_sym);
988			if (ret_val != 1) {
989				dload_error(dlthis, "Failed to create dup of "
990					    "original img pkt\n");
991			}
992		}
993	}
994
995	return ret_val;
996}
997
998/*
999 * Function:	dload_tramp_pkt_update
1000 * Description: Update the duplicate copy of this image packet, which the
1001 *	  trampoline layer is already tracking.  This is call is critical
1002 *	  to make if trampolines were generated anywhere within the
1003 *	  packet and first pass relo continued on the remainder.  The
1004 *	  trampoline layer needs the updates image data so when 2nd
1005 *	  pass relo is done during finalize the image packet can be
1006 *	  written to the target since all relo is done.
1007 */
1008int dload_tramp_pkt_udpate(struct dload_state *dlthis, s16 secnn,
1009			   u32 image_offset, struct image_packet_t *ipacket)
1010{
1011	struct tramp_img_dup_pkt *dup_pkt = NULL;
1012	s32 i;
1013	int ret_val = 0;
1014
1015	/*  Find the image packet in question, the caller needs us to update it
1016	   since a trampoline was previously generated. */
1017	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
1018	if (dup_pkt != NULL) {
1019		for (i = 0; i < dup_pkt->img_pkt.packet_size; i++)
1020			*(dup_pkt->img_pkt.img_data + i) =
1021			    *(ipacket->img_data + i);
1022
1023		ret_val = 1;
1024	} else {
1025		dload_error(dlthis,
1026			    "Unable to find existing DUP pkt for %x, offset %x",
1027			    secnn, image_offset);
1028
1029	}
1030
1031	return ret_val;
1032}
1033
1034/*
1035 * Function:	dload_tramp_finalize
1036 * Description: If any trampolines were created, finalize everything on the
1037 *	  target by allocating the trampoline section on the target,
1038 *	  finalizing the trampoline symbols, finalizing the trampoline
1039 *	  packets (write the new section to target memory) and finalize
1040 *	  the duplicate packets by doing 2nd pass relo over them.
1041 */
1042int dload_tramp_finalize(struct dload_state *dlthis)
1043{
1044	int ret_val = 1;
1045
1046	if (dlthis->tramp.tramp_sect_next_addr != 0) {
1047		/*  Finalize strings into a flat table.  This is needed so it
1048		 * can be added to the debug string table later. */
1049		ret_val = priv_string_tbl_finalize(dlthis);
1050
1051		/*  Do target allocation for section BEFORE finalizing
1052		 * symbols. */
1053		if (ret_val != 0)
1054			ret_val = priv_tramp_sect_tgt_alloc(dlthis);
1055
1056		/*  Finalize symbols with their correct target information and
1057		 * flatten */
1058		if (ret_val != 0)
1059			ret_val = priv_tramp_sym_finalize(dlthis);
1060
1061		/*  Finalize all trampoline packets.  This performs the
1062		 * relocation on the packets as well as writing them to target
1063		 * memory. */
1064		if (ret_val != 0)
1065			ret_val = priv_tramp_pkt_finalize(dlthis);
1066
1067		/*  Perform a 2nd pass relocation on the dup list. */
1068		if (ret_val != 0)
1069			ret_val = priv_dup_pkt_finalize(dlthis);
1070	}
1071
1072	return ret_val;
1073}
1074
1075/*
1076 * Function:	dload_tramp_cleanup
1077 * Description: Release all temporary resources used in the trampoline layer.
1078 *	  Note that the target memory which may have been allocated and
1079 *	  written to store the trampolines is NOT RELEASED HERE since it
1080 *	  is potentially still in use.  It is automatically released
1081 *	  when the module is unloaded.
1082 */
1083void dload_tramp_cleanup(struct dload_state *dlthis)
1084{
1085	struct tramp_info *tramp = &dlthis->tramp;
1086	struct tramp_sym *cur_sym;
1087	struct tramp_string *cur_string;
1088	struct tramp_img_pkt *cur_tramp_pkt;
1089	struct tramp_img_dup_pkt *cur_dup_pkt;
1090	struct tramp_img_dup_relo *cur_dup_relo;
1091
1092	/*  If there were no tramps generated, just return */
1093	if (tramp->tramp_sect_next_addr == 0)
1094		return;
1095
1096	/*  Destroy all tramp information */
1097	for (cur_sym = tramp->symbol_head;
1098	     cur_sym != NULL; cur_sym = tramp->symbol_head) {
1099		tramp->symbol_head = cur_sym->next;
1100		if (tramp->symbol_tail == cur_sym)
1101			tramp->symbol_tail = NULL;
1102
1103		dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
1104	}
1105
1106	if (tramp->final_sym_table != NULL)
1107		dlthis->mysym->dload_deallocate(dlthis->mysym,
1108						tramp->final_sym_table);
1109
1110	for (cur_string = tramp->string_head;
1111	     cur_string != NULL; cur_string = tramp->string_head) {
1112		tramp->string_head = cur_string->next;
1113		if (tramp->string_tail == cur_string)
1114			tramp->string_tail = NULL;
1115
1116		dlthis->mysym->dload_deallocate(dlthis->mysym, cur_string);
1117	}
1118
1119	if (tramp->final_string_table != NULL)
1120		dlthis->mysym->dload_deallocate(dlthis->mysym,
1121						tramp->final_string_table);
1122
1123	for (cur_tramp_pkt = tramp->tramp_pkts;
1124	     cur_tramp_pkt != NULL; cur_tramp_pkt = tramp->tramp_pkts) {
1125		tramp->tramp_pkts = cur_tramp_pkt->next;
1126		dlthis->mysym->dload_deallocate(dlthis->mysym, cur_tramp_pkt);
1127	}
1128
1129	for (cur_dup_pkt = tramp->dup_pkts;
1130	     cur_dup_pkt != NULL; cur_dup_pkt = tramp->dup_pkts) {
1131		tramp->dup_pkts = cur_dup_pkt->next;
1132
1133		for (cur_dup_relo = cur_dup_pkt->relo_chain;
1134		     cur_dup_relo != NULL;
1135		     cur_dup_relo = cur_dup_pkt->relo_chain) {
1136			cur_dup_pkt->relo_chain = cur_dup_relo->next;
1137			dlthis->mysym->dload_deallocate(dlthis->mysym,
1138							cur_dup_relo);
1139		}
1140
1141		dlthis->mysym->dload_deallocate(dlthis->mysym, cur_dup_pkt);
1142	}
1143}
1144